Пример #1
0
 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;
         }
     }
 }
Пример #2
0
        /// <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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        /// <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);
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        /// <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;
                }
            }
        }
Пример #7
0
 /// <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);
 }
Пример #8
0
 /// <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);
 }
Пример #9
0
 /// <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));
 }