Example #1
0
        /**
         * <p>Detects a QR Code in an image, simply.</p>
         *
         * @param hints optional hints to detector
         * @return {@link DetectorResult} encapsulating results of detecting a QR Code
         * @throws ReaderException if no QR Code can be found
         */
        public DetectorResult detect(System.Collections.Hashtable hints)
        {
            MonochromeBitmapSource image = this.image;

            if (!BlackPointEstimationMethod.TWO_D_SAMPLING.Equals(image.getLastEstimationMethod()))
            {
                image.estimateBlackPoint(BlackPointEstimationMethod.TWO_D_SAMPLING, 0);
            }

            FinderPatternFinder finder = new FinderPatternFinder(image);
            FinderPatternInfo   info   = finder.find(hints);

            FinderPattern topLeft    = info.getTopLeft();
            FinderPattern topRight   = info.getTopRight();
            FinderPattern bottomLeft = info.getBottomLeft();

            float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft);

            if (moduleSize < 1.0f)
            {
                throw new ReaderException();
            }
            int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize);

            Version provisionalVersion      = Version.getProvisionalVersionForDimension(dimension);
            int     modulesBetweenFPCenters = provisionalVersion.getDimensionForVersion() - 7;

            AlignmentPattern alignmentPattern = null;

            // Anything above version 1 has an alignment pattern
            if (provisionalVersion.getAlignmentPatternCenters().Length > 0)
            {
                // Guess where a "bottom right" finder pattern would have been
                float bottomRightX = topRight.getX() - topLeft.getX() + bottomLeft.getX();
                float bottomRightY = topRight.getY() - topLeft.getY() + bottomLeft.getY();

                // Estimate that alignment pattern is closer by 3 modules
                // from "bottom right" to known top left location
                float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters;
                int   estAlignmentX       = (int)(topLeft.getX() + correctionToTopLeft * (bottomRightX - topLeft.getX()));
                int   estAlignmentY       = (int)(topLeft.getY() + correctionToTopLeft * (bottomRightY - topLeft.getY()));

                // Kind of arbitrary -- expand search radius before giving up
                for (int i = 4; i <= 16; i <<= 1)
                {
                    try {
                        alignmentPattern = findAlignmentInRegion(moduleSize,
                                                                 estAlignmentX,
                                                                 estAlignmentY,
                                                                 (float)i);
                        break;
                    } catch (ReaderException re) {
                        // try next round
                    }
                }
                if (alignmentPattern == null)
                {
                    throw new ReaderException();
                }
            }

            BitMatrix bits = sampleGrid(image, topLeft, topRight, bottomLeft, alignmentPattern, dimension);

            ResultPoint[] points;
            if (alignmentPattern == null)
            {
                points = new ResultPoint[] { bottomLeft, topLeft, topRight };
            }
            else
            {
                points = new ResultPoint[] { bottomLeft, topLeft, topRight, alignmentPattern };
            }
            return(new DetectorResult(bits, points));
        }
Example #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();
        }
        /**
           * 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();
        }