Esempio n. 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;
         }
     }
 }
Esempio n. 2
0
        /// <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);
        }
Esempio n. 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);
        }
Esempio n. 4
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++)
            {
                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);
        }
Esempio n. 5
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);
        }
Esempio n. 6
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));
 }
Esempio n. 7
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[] 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;
                }
            }
        }
Esempio n. 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);
 }
Esempio n. 9
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
            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);
        }