// 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).
 public static int applyMaskPenaltyRule3(ByteMatrix matrix)
 {
     int penalty = 0;
     sbyte[][] array = matrix.getArray();
     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 += 40;
             }
             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 += 40;
             }
         }
     }
     return penalty;
 }
 // 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.getArray();
     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 += 3;
             }
         }
     }
     return penalty;
 }
 // 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.getArray();
     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;
 }
 // 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.getArray();
     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;
     return Math.Abs((int)(darkRatio * 100 - 50)) / 5 * 10;
 }
 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 (!isValidValue(matrix.get(6, i))) {
         throw new WriterException();
       }
       if (isEmpty(matrix.get(6, i))) {
         matrix.set(6, i, bit);
       }
       // Vertical line.
       if (!isValidValue(matrix.get(i, 6))) {
         throw new WriterException();
       }
       if (isEmpty(matrix.get(i, 6))) {
         matrix.set(i, 6, bit);
       }
     }
 }
        // Embed position detection patterns and surrounding vertical/horizontal separators.
        private static void embedPositionDetectionPatternsAndSeparators(ByteMatrix matrix)
        {
            // Embed three big squares at corners.
            int pdpWidth = POSITION_DETECTION_PATTERN[0].Length;
            // Left top corner.
            embedPositionDetectionPattern(0, 0, matrix);
            // Right top corner.
            embedPositionDetectionPattern(matrix.width() - pdpWidth, 0, matrix);
            // Left bottom corner.
            embedPositionDetectionPattern(0, matrix.width() - pdpWidth, matrix);

            // Embed horizontal separation patterns around the squares.
            int hspWidth = HORIZONTAL_SEPARATION_PATTERN[0].Length;
            // Left top corner.
            embedHorizontalSeparationPattern(0, hspWidth - 1, matrix);
            // Right top corner.
            embedHorizontalSeparationPattern(matrix.width() - hspWidth,
                hspWidth - 1, matrix);
            // Left bottom corner.
            embedHorizontalSeparationPattern(0, matrix.width() - hspWidth, matrix);

            // Embed vertical separation patterns around the squares.
            int vspSize = VERTICAL_SEPARATION_PATTERN.Length;
            // Left top corner.
            embedVerticalSeparationPattern(vspSize, 0, matrix);
            // Right top corner.
            embedVerticalSeparationPattern(matrix.height() - vspSize - 1, 0, matrix);
            // Left bottom corner.
            embedVerticalSeparationPattern(vspSize, matrix.height() - vspSize,
                matrix);
        }
        // Embed type information. On success, modify the matrix.
        public static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix)
        {
            BitVector typeInfoBits = new BitVector();
            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.at(typeInfoBits.size() - 1 - i);

              // 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.set(y1, x1, bit);

              if (i < 8) {
                // Right top corner.
                int x2 = matrix.width() - i - 1;
                int y2 = 8;
                matrix.set(y2, x2, bit);
              } else {
                // Left bottom corner.
                int x2 = 8;
                int y2 = matrix.height() - 7 + (i - 8);
                matrix.set(y2, x2, bit);
              }
            }
        }
        // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true.
        // For debugging purposes, it skips masking process if "getMaskPattern" is -1.
        // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits.
        public static void embedDataBits(BitVector dataBits, int maskPattern, ByteMatrix matrix)
        {
            int bitIndex = 0;
            int direction = -1;
            // Start from the right bottom cell.
            int x = matrix.width() - 1;
            int y = matrix.height() - 1;
            while (x > 0) {
              // Skip the vertical timing pattern.
              if (x == 6) {
                x -= 1;
              }
              while (y >= 0 && y < matrix.height()) {
                for (int i = 0; i < 2; ++i) {
                  int xx = x - i;
                  // Skip the cell if it's not empty.
                  if (!isEmpty(matrix.get(y, xx))) {
                    continue;
                  }
                  int bit;
                  if (bitIndex < dataBits.size()) {
                    bit = dataBits.at(bitIndex);
                    ++bitIndex;
                  } else {
                    // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described
                    // in 8.4.9 of JISX0510:2004 (p. 24).
                    bit = 0;
                  }

                  // Skip masking if mask_pattern is -1.
                  if (maskPattern != -1) {
                    int mask = MaskUtil.getDataMaskBit(maskPattern, xx, y);
                    bit ^= mask;
                  }
                  matrix.set(y, xx, bit);
                }
                y += direction;
              }
              direction = -direction;  // Reverse the direction.
              y += direction;
              x -= 2;  // Move to the left.
            }
            // All bits should be consumed.
            if (bitIndex != dataBits.size()) {
              throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.size());
            }
        }