/// <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 penalty = 0; var 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++) { // Tried to simplify following conditions but failed. if (x + 6 < width && array[y][x] == 1 && array[y][x + 1] == 0 && array[y][x + 2] == 1 && array[y][x + 3] == 1 && array[y][x + 4] == 1 && array[y][x + 5] == 0 && array[y][x + 6] == 1 && ((x + 10 < width && array[y][x + 7] == 0 && array[y][x + 8] == 0 && array[y][x + 9] == 0 && array[y][x + 10] == 0) || (x - 4 >= 0 && array[y][x - 1] == 0 && array[y][x - 2] == 0 && array[y][x - 3] == 0 && array[y][x - 4] == 0))) { penalty += N3; } 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 && ((y + 10 < height && array[y + 7][x] == 0 && array[y + 8][x] == 0 && array[y + 9][x] == 0 && array[y + 10][x] == 0) || (y - 4 >= 0 && array[y - 1][x] == 0 && array[y - 2][x] == 0 && array[y - 3][x] == 0 && array[y - 4][x] == 0))) { penalty += N3; } } } return penalty; }
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; } } }
// Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give // penalty to them. public static int applyMaskPenaltyRule2(ByteMatrix matrix) { int penalty = 0; sbyte[][] 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_Renamed = array[y][x]; if (value_Renamed == array[y][x + 1] && value_Renamed == array[y + 1][x] && value_Renamed == array[y + 1][x + 1]) { penalty += 3; } } } return penalty; }
/// <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; }
/// <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); }
/// <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); }
// Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give // penalty to them. public static int applyMaskPenaltyRule2(ByteMatrix matrix) { int penalty = 0; sbyte[][] 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_Renamed = array[y][x]; if (value_Renamed == array[y][x + 1] && value_Renamed == array[y + 1][x] && value_Renamed == array[y + 1][x + 1]) { penalty += 3; } } } return(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 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 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); }
// 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. Examples: // - 0% => 100 // - 40% => 20 // - 45% => 10 // - 50% => 0 // - 55% => 10 // - 55% => 20 // - 100% => 100 public static int applyMaskPenaltyRule4(ByteMatrix matrix) { int numDarkCells = 0; sbyte[][] 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) { if (array[y][x] == 1) { numDarkCells += 1; } } } int numTotalCells = matrix.Height * matrix.Width; double darkRatio = (double)numDarkCells / numTotalCells; //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" return(System.Math.Abs((int)(darkRatio * 100 - 50)) / 5 * 10); }
public static QRCode encode(String content, ErrorCorrectionLevel ecLevel, IDictionary hints) { // Determine what character encoding has been specified by the caller, if any String encoding = hints == null || !hints.Contains(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET]; if (encoding == null) { encoding = DEFAULT_BYTE_MODE_ENCODING; } bool doSelectMask = hints == null || !hints.Contains(EncodeHintType.QR_DO_MASK_SELECTION) ? false : (bool)hints[EncodeHintType.QR_DO_MASK_SELECTION]; // 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 && !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding)) { CharacterSetECI 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. 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. To pick version size assume length takes maximum bits int bitsNeeded = headerBits.Size + mode.getCharacterCountBits(Version.getVersionForNumber(40)) + 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 = 3; if (doSelectMask) { 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); }
// Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both // vertical and horizontal orders respectively. private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, bool isHorizontal) { int penalty = 0; int numSameBitCells = 0; int prevBit = -1; // Horizontal mode: // for (int i = 0; i < matrix.height(); ++i) { // for (int j = 0; j < matrix.width(); ++j) { // int bit = matrix.get(i, j); // Vertical mode: // for (int i = 0; i < matrix.width(); ++i) { // for (int j = 0; j < matrix.height(); ++j) { // int bit = matrix.get(j, i); int iLimit = isHorizontal ? matrix.Height : matrix.Width; int jLimit = isHorizontal ? matrix.Width : matrix.Height; sbyte[][] array = matrix.Array; for (int i = 0; i < iLimit; ++i) { for (int j = 0; j < jLimit; ++j) { int bit = isHorizontal ? array[i][j] : array[j][i]; if (bit == prevBit) { numSameBitCells += 1; // Found five repetitive cells with the same color (bit). // We'll give penalty of 3. if (numSameBitCells == 5) { penalty += 3; } else if (numSameBitCells > 5) { // After five repetitive cells, we'll add the penalty one // by one. penalty += 1; } } else { numSameBitCells = 1; // Include the cell itself. prevBit = bit; } } numSameBitCells = 0; // Clear at each row/column. } return penalty; }
/// <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> /// 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 // http://zxingnet.codeplex.com/discussions/399045 if (hints != null && hints.ContainsKey(EncodeHintType.DISABLE_ECI) && (bool)hints[EncodeHintType.DISABLE_ECI]) { generateECI = false; } // 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) { 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> /// 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> /// 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> /// 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 bool hasEncodingHint = hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET); #if !SILVERLIGHT || WINDOWS_PHONE var encoding = hints == null || !hints.ContainsKey(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET]; if (encoding == null) { encoding = DEFAULT_BYTE_MODE_ENCODING; } var generateECI = hasEncodingHint || !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 var generateECI = hasEncodingHint; #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. 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) { var eciIsExplicitDisabled = (hints != null && hints.ContainsKey(EncodeHintType.DISABLE_ECI) && hints[EncodeHintType.DISABLE_ECI] != null && Convert.ToBoolean(hints[EncodeHintType.DISABLE_ECI].ToString())); if (!eciIsExplicitDisabled) { appendECI(eci, headerBits); } } } // Append the FNC1 mode header for GS1 formatted data if applicable var hasGS1FormatHint = hints != null && hints.ContainsKey(EncodeHintType.GS1_FORMAT); if (hasGS1FormatHint && hints[EncodeHintType.GS1_FORMAT] != null && Convert.ToBoolean(hints[EncodeHintType.GS1_FORMAT].ToString())) { // GS1 formatted codes are prefixed with a FNC1 in first position mode header appendModeInfo(Mode.FNC1_FIRST_POSITION, 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; if (hints != null && hints.ContainsKey(EncodeHintType.QR_VERSION)) { int versionNumber = Int32.Parse(hints[EncodeHintType.QR_VERSION].ToString()); version = Version.getVersionForNumber(versionNumber); int bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, version); if (!willFit(bitsNeeded, version, ecLevel)) { throw new WriterException("Data too big for requested version"); } } else { 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); }
// 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. Examples: // - 0% => 100 // - 40% => 20 // - 45% => 10 // - 50% => 0 // - 55% => 10 // - 55% => 20 // - 100% => 100 public static int applyMaskPenaltyRule4(ByteMatrix matrix) { int numDarkCells = 0; sbyte[][] 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) { if (array[y][x] == 1) { numDarkCells += 1; } } } int numTotalCells = matrix.Height * matrix.Width; double darkRatio = (double)numDarkCells / numTotalCells; //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" return System.Math.Abs((int)(darkRatio * 100 - 50)) / 5 * 10; }
/// <summary> /// Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both /// vertical and horizontal orders respectively. /// </summary> /// <param name="matrix">The matrix.</param> /// <param name="isHorizontal">if set to <c>true</c> [is horizontal].</param> /// <returns></returns> private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, bool isHorizontal) { int penalty = 0; int iLimit = isHorizontal ? matrix.Height : matrix.Width; int jLimit = isHorizontal ? matrix.Width : matrix.Height; var array = matrix.Array; for (int i = 0; i < iLimit; i++) { int numSameBitCells = 0; int prevBit = -1; for (int j = 0; j < jLimit; j++) { int bit = isHorizontal ? array[i][j] : array[j][i]; if (bit == prevBit) { numSameBitCells++; } else { if (numSameBitCells >= 5) { penalty += N1 + (numSameBitCells - 5); } numSameBitCells = 1; // Include the cell itself. prevBit = bit; } } if (numSameBitCells >= 5) { penalty += N1 + (numSameBitCells - 5); } } return penalty; }
/// <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); }