Exemple #1
0
        /**
         * See {@link #sizeOfBlackWhiteBlackRun(int, int, int, int)}; computes the total width of
         * a finder pattern by looking for a black-white-black run from the center in the direction
         * of another point (another finder pattern center), and in the opposite direction too.</p>
         */
        private float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY)
        {
            float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);

            // Now count other way -- don't run off image though of course
            int otherToX = fromX - (toX - fromX);

            if (otherToX < 0)
            {
                // "to" should the be the first value not included, so, the first value off
                // the edge is -1
                otherToX = -1;
            }
            else if (otherToX >= image.getWidth())
            {
                otherToX = image.getWidth();
            }
            int otherToY = fromY - (toY - fromY);

            if (otherToY < 0)
            {
                otherToY = -1;
            }
            else if (otherToY >= image.getHeight())
            {
                otherToY = image.getHeight();
            }
            result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);
            return(result - 1.0f); // -1 because we counted the middle pixel twice
        }
Exemple #2
0
        /**
         * We're going to examine rows from the middle outward, searching alternately above and below the
         * middle, and farther out each time. rowStep is the number of rows between each successive
         * attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then
         * middle + rowStep, then middle - (2 * rowStep), etc.
         * rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily
         * decided that moving up and down by about 1/16 of the image is pretty good; we try more of the
         * image if "trying harder".
         *
         * @param image The image to decode
         * @param hints Any hints that were requested
         * @return The contents of the decoded barcode
         * @throws ReaderException Any spontaneous errors which occur
         */
        private Result doDecode(MonochromeBitmapSource image, System.Collections.Hashtable hints)
        {
            int      width  = image.getWidth();
            int      height = image.getHeight();
            BitArray row    = new BitArray(width);

            int  middle    = height >> 1;
            bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER);
            int  rowStep   = Math.Max(1, height >> (tryHarder ? 7 : 4));
            int  MaxLines;

            if (tryHarder)
            {
                MaxLines = height; // Look at the whole image, not just the center
            }
            else
            {
                MaxLines = 9; // Nine rows spaced 1/16 apart is roughly the middle half of the image
            }

            for (int x = 0; x < MaxLines; x++)
            {
                // Scanning from the middle out. Determine which row we're looking at next:
                int  rowStepsAboveOrBelow = (x + 1) >> 1;
                bool isAbove   = (x & 0x01) == 0; // i.e. is x even?
                int  rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
                if (rowNumber < 0 || rowNumber >= height)
                {
                    // Oops, if we run off the top or bottom, stop
                    break;
                }

                // Estimate black point for this row and load it:
                try {
                    image.estimateBlackPoint(BlackPointEstimationMethod.ROW_SAMPLING, rowNumber);
                } catch (ReaderException re) {
                    continue;
                }

                image.getBlackRow(rowNumber, row, 0, width);

                // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
                // handle decoding upside down barcodes.
                for (int attempt = 0; attempt < 2; attempt++)
                {
                    if (attempt == 1)  // trying again?
                    {
                        row.reverse(); // reverse the row and continue
                    }
                    try {
                        // Look for a barcode
                        Result result = decodeRow(rowNumber, row, hints);
                        // We found our barcode
                        if (attempt == 1)
                        {
                            // But it was upside down, so note that
                            result.putMetadata(ResultMetadataType.ORIENTATION, 180);
                            // And remember to flip the result points horizontally.
                            ResultPoint[] points = result.getResultPoints();
                            points[0] = (ResultPoint) new GenericResultPoint(width - points[0].getX() - 1, points[0].getY());
                            points[1] = (ResultPoint) new GenericResultPoint(width - points[1].getX() - 1, points[1].getY());
                        }
                        return(result);
                    } catch (ReaderException re) {
                        // continue -- just couldn't decode this row
                    }
                }
            }

            throw new ReaderException();
        }
Exemple #3
0
        /**
         * This method detects a Data Matrix code in a "pure" image -- that is, pure monochrome image
         * which contains only an unrotated, unskewed, image of a Data Matrix code, with some white border
         * around it. This is a specialized method that works exceptionally fast in this special
         * case.
         */
        private static BitMatrix extractPureBits(MonochromeBitmapSource image)
        {
            // Now need to determine module size in pixels

            int height       = image.getHeight();
            int width        = image.getWidth();
            int minDimension = Math.Min(height, width);

            // First, skip white border by tracking diagonally from the top left down and to the right:
            int borderWidth = 0;

            while (borderWidth < minDimension && !image.isBlack(borderWidth, borderWidth))
            {
                borderWidth++;
            }
            if (borderWidth == minDimension)
            {
                throw new ReaderException();
            }

            // And then keep tracking across the top-left black module to determine module size
            int moduleEnd = borderWidth + 1;

            while (moduleEnd < width && image.isBlack(moduleEnd, borderWidth))
            {
                moduleEnd++;
            }
            if (moduleEnd == width)
            {
                throw new ReaderException();
            }

            int moduleSize = moduleEnd - borderWidth;

            // And now find where the bottommost black module on the first column ends
            int columnEndOfSymbol = height - 1;

            while (columnEndOfSymbol >= 0 && !image.isBlack(borderWidth, columnEndOfSymbol))
            {
                columnEndOfSymbol--;
            }
            if (columnEndOfSymbol < 0)
            {
                throw new ReaderException();
            }
            columnEndOfSymbol++;

            // Make sure width of barcode is a multiple of module size
            if ((columnEndOfSymbol - borderWidth) % moduleSize != 0)
            {
                throw new ReaderException();
            }
            int dimension = (columnEndOfSymbol - borderWidth) / moduleSize;

            // Push in the "border" by half the module width so that we start
            // sampling in the middle of the module. Just in case the image is a
            // little off, this will help recover.
            borderWidth += moduleSize >> 1;

            int sampleDimension = borderWidth + (dimension - 1) * moduleSize;

            if (sampleDimension >= width || sampleDimension >= height)
            {
                throw new ReaderException();
            }

            // Now just read off the bits
            BitMatrix bits = new BitMatrix(dimension);

            for (int i = 0; i < dimension; i++)
            {
                int iOffset = borderWidth + i * moduleSize;
                for (int j = 0; j < dimension; j++)
                {
                    if (image.isBlack(borderWidth + j * moduleSize, iOffset))
                    {
                        bits.set(i, j);
                    }
                }
            }
            return(bits);
        }
        /**
           * This method detects a Data Matrix code in a "pure" image -- that is, pure monochrome image
           * which contains only an unrotated, unskewed, image of a Data Matrix code, with some white border
           * around it. This is a specialized method that works exceptionally fast in this special
           * case.
           */
        private static BitMatrix extractPureBits(MonochromeBitmapSource image)
        {
            // Now need to determine module size in pixels

            int height = image.getHeight();
            int width = image.getWidth();
            int minDimension = Math.Min(height, width);

            // First, skip white border by tracking diagonally from the top left down and to the right:
            int borderWidth = 0;
            while (borderWidth < minDimension && !image.isBlack(borderWidth, borderWidth)) {
              borderWidth++;
            }
            if (borderWidth == minDimension) {
              throw new ReaderException();
            }

            // And then keep tracking across the top-left black module to determine module size
            int moduleEnd = borderWidth + 1;
            while (moduleEnd < width && image.isBlack(moduleEnd, borderWidth)) {
              moduleEnd++;
            }
            if (moduleEnd == width) {
              throw new ReaderException();
            }

            int moduleSize = moduleEnd - borderWidth;

            // And now find where the bottommost black module on the first column ends
            int columnEndOfSymbol = height - 1;
            while (columnEndOfSymbol >= 0 && !image.isBlack(borderWidth, columnEndOfSymbol)) {
                columnEndOfSymbol--;
            }
            if (columnEndOfSymbol < 0) {
              throw new ReaderException();
            }
            columnEndOfSymbol++;

            // Make sure width of barcode is a multiple of module size
            if ((columnEndOfSymbol - borderWidth) % moduleSize != 0) {
              throw new ReaderException();
            }
            int dimension = (columnEndOfSymbol - borderWidth) / moduleSize;

            // Push in the "border" by half the module width so that we start
            // sampling in the middle of the module. Just in case the image is a
            // little off, this will help recover.
            borderWidth += moduleSize >> 1;

            int sampleDimension = borderWidth + (dimension - 1) * moduleSize;
            if (sampleDimension >= width || sampleDimension >= height) {
              throw new ReaderException();
            }

            // Now just read off the bits
            BitMatrix bits = new BitMatrix(dimension);
            for (int i = 0; i < dimension; i++) {
              int iOffset = borderWidth + i * moduleSize;
              for (int j = 0; j < dimension; j++) {
                if (image.isBlack(borderWidth + j * moduleSize, iOffset)) {
                  bits.set(i, j);
                }
              }
            }
            return bits;
        }
        /**
           * We're going to examine rows from the middle outward, searching alternately above and below the
           * middle, and farther out each time. rowStep is the number of rows between each successive
           * attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then
           * middle + rowStep, then middle - (2 * rowStep), etc.
           * rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily
           * decided that moving up and down by about 1/16 of the image is pretty good; we try more of the
           * image if "trying harder".
           *
           * @param image The image to decode
           * @param hints Any hints that were requested
           * @return The contents of the decoded barcode
           * @throws ReaderException Any spontaneous errors which occur
           */
        private Result doDecode(MonochromeBitmapSource image, System.Collections.Hashtable hints)
        {
            int width = image.getWidth();
            int height = image.getHeight();
            BitArray row = new BitArray(width);

            int middle = height >> 1;
            bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER);
            int rowStep = Math.Max(1, height >> (tryHarder ? 7 : 4));
            int MaxLines;
            if (tryHarder) {
              MaxLines = height; // Look at the whole image, not just the center
            } else {
              MaxLines = 9; // Nine rows spaced 1/16 apart is roughly the middle half of the image
            }

            for (int x = 0; x < MaxLines; x++) {

              // Scanning from the middle out. Determine which row we're looking at next:
              int rowStepsAboveOrBelow = (x + 1) >> 1;
              bool isAbove = (x & 0x01) == 0; // i.e. is x even?
              int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
              if (rowNumber < 0 || rowNumber >= height) {
                // Oops, if we run off the top or bottom, stop
                break;
              }

              // Estimate black point for this row and load it:
              try {
                image.estimateBlackPoint(BlackPointEstimationMethod.ROW_SAMPLING, rowNumber);
              } catch (ReaderException re) {
                continue;
              }

              image.getBlackRow(rowNumber, row,0, width);

              // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
              // handle decoding upside down barcodes.
              for (int attempt = 0; attempt < 2; attempt++) {
                if (attempt == 1) { // trying again?
                  row.reverse(); // reverse the row and continue
                }
                try {
                  // Look for a barcode
                  Result result = decodeRow(rowNumber, row, hints);
                  // We found our barcode
                  if (attempt == 1) {
                    // But it was upside down, so note that
                    result.putMetadata(ResultMetadataType.ORIENTATION, 180);
                    // And remember to flip the result points horizontally.
                    ResultPoint[] points = result.getResultPoints();
                    points[0] = (ResultPoint) new GenericResultPoint(width - points[0].getX() - 1, points[0].getY());
                    points[1] = (ResultPoint)new GenericResultPoint(width - points[1].getX() - 1, points[1].getY());
                  }
                  return result;
                } catch (ReaderException re) {
                  // continue -- just couldn't decode this row
                }
              }
            }

            throw new ReaderException();
        }
Exemple #6
0
        /**
         * <p>Like {@link #crossCheckVertical(int, int, int, int)}, and in fact is basically identical,
         * except it reads horizontally instead of vertically. This is used to cross-cross
         * check a vertical cross check and locate the real center of the alignment pattern.</p>
         */
        private float crossCheckHorizontal(int startJ, int centerI, int maxCount, int originalStateCountTotal)
        {
            MonochromeBitmapSource image = this.image;

            int maxJ = image.getWidth();

            int[] stateCount = getCrossCheckStateCount();

            int j = startJ;

            while (j >= 0 && image.isBlack(j, centerI))
            {
                stateCount[2]++;
                j--;
            }
            if (j < 0)
            {
                return(float.NaN);
            }
            while (j >= 0 && !image.isBlack(j, centerI) && stateCount[1] <= maxCount)
            {
                stateCount[1]++;
                j--;
            }
            if (j < 0 || stateCount[1] > maxCount)
            {
                return(float.NaN);
            }
            while (j >= 0 && image.isBlack(j, centerI) && stateCount[0] <= maxCount)
            {
                stateCount[0]++;
                j--;
            }
            if (stateCount[0] > maxCount)
            {
                return(float.NaN);
            }

            j = startJ + 1;
            while (j < maxJ && image.isBlack(j, centerI))
            {
                stateCount[2]++;
                j++;
            }
            if (j == maxJ)
            {
                return(float.NaN);
            }
            while (j < maxJ && !image.isBlack(j, centerI) && stateCount[3] < maxCount)
            {
                stateCount[3]++;
                j++;
            }
            if (j == maxJ || stateCount[3] >= maxCount)
            {
                return(float.NaN);
            }
            while (j < maxJ && image.isBlack(j, centerI) && stateCount[4] < maxCount)
            {
                stateCount[4]++;
                j++;
            }
            if (stateCount[4] >= maxCount)
            {
                return(float.NaN);
            }

            // If we found a finder-pattern-like section, but its size is significantly different than
            // the original, assume it's a false positive
            int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];

            if (5 * Math.Abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal)
            {
                return(float.NaN);
            }

            return(foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : float.NaN);
        }