Exemple #1
0
        public virtual Result Decode(BinaryBitmap image, System.Collections.Hashtable hints)
        {
            DecoderResult decoderResult;

            ResultPoint[] points;
            if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE))
            {
                BitMatrix bits = extractPureBits(image.BlackMatrix);
                decoderResult = decoder.decode(bits);
                points        = NO_POINTS;
            }
            else
            {
                DetectorResult detectorResult = new Detector(image.BlackMatrix).detect(hints);
                decoderResult = decoder.decode(detectorResult.Bits);
                points        = detectorResult.Points;
            }

            Result result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.QR_CODE);

            if (decoderResult.ByteSegments != null)
            {
                result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult.ByteSegments);
            }
            if (decoderResult.ECLevel != null)
            {
                result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.ECLevel.ToString());
            }
            return(result);
        }
Exemple #2
0
 public FinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback)
 {
     this.image                = image;
     this.possibleCenters      = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
     this.crossCheckStateCount = new int[5];
     this.resultPointCallback  = resultPointCallback;
 }
Exemple #3
0
        private static BitMatrix sampleGrid(BitMatrix matrix, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, ResultPoint bottomRight, int dimension)
        {
            // Note that unlike the QR Code sampler, we didn't find the center of modules, but the
            // very corners. So there is no 0.5f here; 0.0f is right.
            GridSampler sampler = GridSampler.Instance;

            return(sampler.sampleGrid(matrix, dimension, 0.0f, 0.0f, dimension, 0.0f, dimension, dimension, 0.0f, dimension, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y));            // p4FromY
        }
Exemple #4
0
        protected internal virtual DetectorResult ProcessFinderPatternInfo(FinderPatternInfo info)
        {
            FinderPattern topLeft    = info.TopLeft;
            FinderPattern topRight   = info.TopRight;
            FinderPattern bottomLeft = info.BottomLeft;

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

            if (moduleSize < 1.0f)
            {
                throw ReaderException.Instance;
            }
            int     dimension               = computeDimension(topLeft, topRight, bottomLeft, moduleSize);
            Version provisionalVersion      = Version.getProvisionalVersionForDimension(dimension);
            int     modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7;

            AlignmentPattern alignmentPattern = null;

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

                // Estimate that alignment pattern is closer by 3 modules
                // from "bottom right" to known top left location
                //UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
                float correctionToTopLeft = 1.0f - 3.0f / modulesBetweenFPCenters;
                //UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
                int estAlignmentX = (int)(topLeft.X + correctionToTopLeft * (bottomRightX - topLeft.X));
                //UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
                int estAlignmentY = (int)(topLeft.Y + correctionToTopLeft * (bottomRightY - topLeft.Y));

                // Kind of arbitrary -- expand search radius before giving up
                for (int i = 4; i <= 16; i <<= 1)
                {
                    try
                    {
                        //UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
                        alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, i);
                        break;
                    }
                    catch (ReaderException)
                    {
                        // try next round
                    }
                }
                // If we didn't find alignment pattern... well try anyway without it
            }

            PerspectiveTransform transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);

            BitMatrix bits = sampleGrid(_image, transform, dimension);

            ResultPoint[] points = alignmentPattern == null ? new ResultPoint[] { bottomLeft, topLeft, topRight } : new ResultPoint[] { bottomLeft, topLeft, topRight, alignmentPattern };
            return(new DetectorResult(bits, points));
        }
		/// <param name="bitMatrix">{@link BitMatrix} to parse
		/// </param>
		/// <throws>  ReaderException if dimension is not >= 21 and 1 mod 4 </throws>
		internal BitMatrixParser(BitMatrix bitMatrix)
		{
			int dimension = bitMatrix.Dimension;
			if (dimension < 21 || (dimension & 0x03) != 1)
			{
				throw ReaderException.Instance;
			}
			this.bitMatrix = bitMatrix;
		}
Exemple #6
0
        /// <param name="bitMatrix">{@link BitMatrix} to parse
        /// </param>
        /// <throws>  ReaderException if dimension is not >= 21 and 1 mod 4 </throws>
        internal BitMatrixParser(BitMatrix bitMatrix)
        {
            int dimension = bitMatrix.Dimension;

            if (dimension < 21 || (dimension & 0x03) != 1)
            {
                throw ReaderException.Instance;
            }
            this.bitMatrix = bitMatrix;
        }
		/// <summary> <p>Creates a finder that will look in a portion of the whole image.</p>
		/// 
		/// </summary>
		/// <param name="image">image to search
		/// </param>
		/// <param name="startX">left column from which to start searching
		/// </param>
		/// <param name="startY">top row from which to start searching
		/// </param>
		/// <param name="width">width of region to search
		/// </param>
		/// <param name="height">height of region to search
		/// </param>
		/// <param name="moduleSize">estimated module size so far
		/// </param>
		internal AlignmentPatternFinder(BitMatrix image, int startX, int startY, int width, int height, float moduleSize, ResultPointCallback resultPointCallback)
		{
			this.image = image;
			this.possibleCenters = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(5));
			this.startX = startX;
			this.startY = startY;
			this.width = width;
			this.height = height;
			this.moduleSize = moduleSize;
			this.crossCheckStateCount = new int[3];
			this.resultPointCallback = resultPointCallback;
		}
 /// <summary> <p>Creates a finder that will look in a portion of the whole image.</p>
 ///
 /// </summary>
 /// <param name="image">image to search
 /// </param>
 /// <param name="startX">left column from which to start searching
 /// </param>
 /// <param name="startY">top row from which to start searching
 /// </param>
 /// <param name="width">width of region to search
 /// </param>
 /// <param name="height">height of region to search
 /// </param>
 /// <param name="moduleSize">estimated module size so far
 /// </param>
 internal AlignmentPatternFinder(BitMatrix image, int startX, int startY, int width, int height, float moduleSize, ResultPointCallback resultPointCallback)
 {
     this.image                = image;
     this.possibleCenters      = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(5));
     this.startX               = startX;
     this.startY               = startY;
     this.width                = width;
     this.height               = height;
     this.moduleSize           = moduleSize;
     this.crossCheckStateCount = new int[3];
     this.resultPointCallback  = resultPointCallback;
 }
Exemple #9
0
 /// <summary> <p>Implementations of this method reverse the data masking process applied to a QR Code and
 /// make its bits ready to read.</p>
 ///
 /// </summary>
 /// <param name="bits">representation of QR Code bits
 /// </param>
 /// <param name="dimension">dimension of QR Code, represented by bits, being unmasked
 /// </param>
 internal void  unmaskBitMatrix(BitMatrix bits, int dimension)
 {
     for (int i = 0; i < dimension; i++)
     {
         for (int j = 0; j < dimension; j++)
         {
             if (isMasked(i, j))
             {
                 bits.flip(j, i);
             }
         }
     }
 }
		/// <param name="bitMatrix">{@link BitMatrix} to parse
		/// </param>
		/// <throws>  ReaderException if dimension is < 10 or > 144 or not 0 mod 2 </throws>
		internal BitMatrixParser(BitMatrix bitMatrix)
		{
			int dimension = bitMatrix.Dimension;
			if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0)
			{
				throw ReaderException.Instance;
			}
			
			version = readVersion(bitMatrix);
			this.mappingBitMatrix = extractDataRegion(bitMatrix);
			// TODO(bbrown): Make this work for rectangular symbols
			this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.Dimension);
		}
Exemple #11
0
        /// <summary> <p>Creates the version object based on the dimension of the original bit matrix from
        /// the datamatrix code.</p>
        ///
        /// <p>See ISO 16022:2006 Table 7 - ECC 200 symbol attributes</p>
        ///
        /// </summary>
        /// <param name="bitMatrix">Original {@link BitMatrix} including alignment patterns
        /// </param>
        /// <returns> {@link Version} encapsulating the Data Matrix Code's "version"
        /// </returns>
        /// <throws>  ReaderException if the dimensions of the mapping matrix are not valid </throws>
        /// <summary> Data Matrix dimensions.
        /// </summary>
        internal Version readVersion(BitMatrix bitMatrix)
        {
            if (version != null)
            {
                return(version);
            }

            // TODO(bbrown): make this work for rectangular dimensions as well.
            int numRows    = bitMatrix.Dimension;
            int numColumns = numRows;

            return(Version.getVersionForDimensions(numRows, numColumns));
        }
Exemple #12
0
		/// <summary> <p>Implementations of this method reverse the data masking process applied to a QR Code and
		/// make its bits ready to read.</p>
		/// 
		/// </summary>
		/// <param name="bits">representation of QR Code bits
		/// </param>
		/// <param name="dimension">dimension of QR Code, represented by bits, being unmasked
		/// </param>
		internal void  unmaskBitMatrix(BitMatrix bits, int dimension)
		{
			for (int i = 0; i < dimension; i++)
			{
				for (int j = 0; j < dimension; j++)
				{
					if (isMasked(i, j))
					{
						bits.flip(j, i);
					}
				}
			}
		}
Exemple #13
0
        /// <param name="bitMatrix">{@link BitMatrix} to parse
        /// </param>
        /// <throws>  ReaderException if dimension is < 10 or > 144 or not 0 mod 2 </throws>
        internal BitMatrixParser(BitMatrix bitMatrix)
        {
            int dimension = bitMatrix.Dimension;

            if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0)
            {
                throw ReaderException.Instance;
            }

            version = readVersion(bitMatrix);
            this.mappingBitMatrix = extractDataRegion(bitMatrix);
            // TODO(bbrown): Make this work for rectangular symbols
            this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.Dimension);
        }
Exemple #14
0
        private static BitMatrix sampleGrid(BitMatrix image, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint bottomRight, int dimension)
        {
            // We make up the top right point for now, based on the others.
            // TODO: we actually found a fourth corner above and figured out which of two modules
            // it was the corner of. We could use that here and adjust for perspective distortion.
            float topRightX = (bottomRight.X - bottomLeft.X) + topLeft.X;
            float topRightY = (bottomRight.Y - bottomLeft.Y) + topLeft.Y;

            // Note that unlike in the QR Code sampler, we didn't find the center of modules, but the
            // very corners. So there is no 0.5f here; 0.0f is right.
            GridSampler sampler = GridSampler.Instance;

            return(sampler.sampleGrid(image, dimension, 0.0f, 0.0f, dimension, 0.0f, dimension, dimension, 0.0f, dimension, topLeft.X, topLeft.Y, topRightX, topRightY, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y));
        }
		/// <summary> <p>Creates the version object based on the dimension of the original bit matrix from 
		/// the datamatrix code.</p>
		/// 
		/// <p>See ISO 16022:2006 Table 7 - ECC 200 symbol attributes</p>
		/// 
		/// </summary>
		/// <param name="bitMatrix">Original {@link BitMatrix} including alignment patterns
		/// </param>
		/// <returns> {@link Version} encapsulating the Data Matrix Code's "version"
		/// </returns>
		/// <throws>  ReaderException if the dimensions of the mapping matrix are not valid </throws>
		/// <summary> Data Matrix dimensions.
		/// </summary>
		internal Version readVersion(BitMatrix bitMatrix)
		{
			
			if (version != null)
			{
				return version;
			}
			
			// TODO(bbrown): make this work for rectangular dimensions as well.
			int numRows = bitMatrix.Dimension;
			int numColumns = numRows;
			
			return Version.getVersionForDimensions(numRows, numColumns);
		}
Exemple #16
0
		/// <summary> <p>Convenience method that can decode a Data Matrix Code represented as a 2D array of booleans.
		/// "true" is taken to mean a black module.</p>
		/// 
		/// </summary>
		/// <param name="image">booleans representing white/black Data Matrix Code modules
		/// </param>
		/// <returns> text and bytes encoded within the Data Matrix Code
		/// </returns>
		/// <throws>  ReaderException if the Data Matrix Code cannot be decoded </throws>
		public DecoderResult decode(bool[][] image)
		{
			int dimension = image.Length;
			BitMatrix bits = new BitMatrix(dimension);
			for (int i = 0; i < dimension; i++)
			{
				for (int j = 0; j < dimension; j++)
				{
					if (image[i][j])
					{
						bits.set_Renamed(j, i);
					}
				}
			}
			return decode(bits);
		}
Exemple #17
0
        /// <summary> <p>Extracts the data region from a {@link BitMatrix} that contains
        /// alignment patterns.</p>
        ///
        /// </summary>
        /// <param name="bitMatrix">Original {@link BitMatrix} with alignment patterns
        /// </param>
        /// <returns> BitMatrix that has the alignment patterns removed
        /// </returns>
        internal BitMatrix extractDataRegion(BitMatrix bitMatrix)
        {
            int symbolSizeRows    = version.SymbolSizeRows;
            int symbolSizeColumns = version.SymbolSizeColumns;

            // TODO(bbrown): Make this work with rectangular codes
            if (bitMatrix.Dimension != symbolSizeRows)
            {
                throw new System.ArgumentException("Dimension of bitMarix must match the version size");
            }

            int dataRegionSizeRows    = version.DataRegionSizeRows;
            int dataRegionSizeColumns = version.DataRegionSizeColumns;

            int numDataRegionsRow    = symbolSizeRows / dataRegionSizeRows;
            int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;

            int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;
            //int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;

            // TODO(bbrown): Make this work with rectangular codes
            BitMatrix bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionRow);

            for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow)
            {
                int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;
                for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn)
                {
                    int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns;
                    for (int i = 0; i < dataRegionSizeRows; ++i)
                    {
                        int readRowOffset  = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;
                        int writeRowOffset = dataRegionRowOffset + i;
                        for (int j = 0; j < dataRegionSizeColumns; ++j)
                        {
                            int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;
                            if (bitMatrix.get_Renamed(readColumnOffset, readRowOffset))
                            {
                                int writeColumnOffset = dataRegionColumnOffset + j;
                                bitMatrixWithoutAlignment.set_Renamed(writeColumnOffset, writeRowOffset);
                            }
                        }
                    }
                }
            }
            return(bitMatrixWithoutAlignment);
        }
Exemple #18
0
        /// <summary> <p>Convenience method that can decode a PDF417 Code represented as a 2D array of booleans.
        /// "true" is taken to mean a black module.</p>
        ///
        /// </summary>
        /// <param name="image">booleans representing white/black PDF417 modules
        /// </param>
        /// <returns> text and bytes encoded within the PDF417 Code
        /// </returns>
        /// <throws>  ReaderException if the PDF417 Code cannot be decoded </throws>
        public DecoderResult decode(bool[][] image)
        {
            int       dimension = image.Length;
            BitMatrix bits      = new BitMatrix(dimension);

            for (int i = 0; i < dimension; i++)
            {
                for (int j = 0; j < dimension; j++)
                {
                    if (image[j][i])
                    {
                        bits.set_Renamed(j, i);
                    }
                }
            }
            return(decode(bits));
        }
Exemple #19
0
        /// <param name="matrix">row of black/white values to search
        /// </param>
        /// <param name="column">x position to start search
        /// </param>
        /// <param name="row">y position to start search
        /// </param>
        /// <param name="width">the number of pixels to search on this row
        /// </param>
        /// <param name="pattern">pattern of counts of number of black and white pixels that are
        /// being searched for as a pattern
        /// </param>
        /// <returns> start/end horizontal offset of guard pattern, as an array of two ints.
        /// </returns>
        private static int[] findGuardPattern(BitMatrix matrix, int column, int row, int width, bool whiteFirst, int[] pattern)
        {
            int patternLength = pattern.Length;

            // TODO: Find a way to cache this array, as this method is called hundreds of times
            // per image, and we want to allocate as seldom as possible.
            int[] counters = new int[patternLength];
            bool  isWhite  = whiteFirst;

            int counterPosition = 0;
            int patternStart    = column;

            for (int x = column; x < column + width; x++)
            {
                bool pixel = matrix.get_Renamed(x, row);
                if (pixel ^ isWhite)
                {
                    counters[counterPosition]++;
                }
                else
                {
                    if (counterPosition == patternLength - 1)
                    {
                        if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE)
                        {
                            return(new int[] { patternStart, x });
                        }
                        patternStart += counters[0] + counters[1];
                        for (int y = 2; y < patternLength; y++)
                        {
                            counters[y - 2] = counters[y];
                        }
                        counters[patternLength - 2] = 0;
                        counters[patternLength - 1] = 0;
                        counterPosition--;
                    }
                    else
                    {
                        counterPosition++;
                    }
                    counters[counterPosition] = 1;
                    isWhite = !isWhite;
                }
            }
            return(null);
        }
Exemple #20
0
        /// <summary> <p>Detects a PDF417 Code in an image. Only checks 0 and 180 degree rotations.</p>
        ///
        /// </summary>
        /// <param name="hints">optional hints to detector
        /// </param>
        /// <returns> {@link DetectorResult} encapsulating results of detecting a PDF417 Code
        /// </returns>
        /// <throws>  ReaderException if no PDF417 Code can be found </throws>
        public DetectorResult detect(System.Collections.Hashtable hints)
        {
            // Fetch the 1 bit matrix once up front.
            BitMatrix matrix = image.BlackMatrix;

            // Try to find the vertices assuming the image is upright.
            ResultPoint[] vertices = findVertices(matrix);
            if (vertices == null)
            {
                // Maybe the image is rotated 180 degrees?
                vertices = findVertices180(matrix);
                if (vertices != null)
                {
                    correctCodeWordVertices(vertices, true);
                }
            }
            else
            {
                correctCodeWordVertices(vertices, false);
            }

            if (vertices != null)
            {
                float moduleWidth = computeModuleWidth(vertices);
                if (moduleWidth < 1.0f)
                {
                    throw ReaderException.Instance;
                }

                int dimension = computeDimension(vertices[4], vertices[6], vertices[5], vertices[7], moduleWidth);
                if (dimension < 1)
                {
                    throw ReaderException.Instance;
                }

                // Deskew and sample image.
                BitMatrix bits = sampleGrid(matrix, vertices[4], vertices[5], vertices[6], vertices[7], dimension);
                return(new DetectorResult(bits, new ResultPoint[] { vertices[4], vertices[5], vertices[6], vertices[7] }));
            }
            else
            {
                throw ReaderException.Instance;
            }
        }
Exemple #21
0
        /// <summary> See ISO 18004:2006 Annex E</summary>
        internal BitMatrix buildFunctionPattern()
        {
            int       dimension = DimensionForVersion;
            BitMatrix bitMatrix = new BitMatrix(dimension);

            // Top left finder pattern + separator + format
            bitMatrix.setRegion(0, 0, 9, 9);
            // Top right finder pattern + separator + format
            bitMatrix.setRegion(dimension - 8, 0, 8, 9);
            // Bottom left finder pattern + separator + format
            bitMatrix.setRegion(0, dimension - 8, 9, 8);

            // Alignment patterns
            int max = _alignmentPatternCenters.Length;

            for (int x = 0; x < max; x++)
            {
                int i = _alignmentPatternCenters[x] - 2;
                for (int y = 0; y < max; y++)
                {
                    if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0))
                    {
                        // No alignment patterns near the three finder paterns
                        continue;
                    }
                    bitMatrix.setRegion(_alignmentPatternCenters[y] - 2, i, 5, 5);
                }
            }

            // Vertical timing pattern
            bitMatrix.setRegion(6, 9, 1, dimension - 17);
            // Horizontal timing pattern
            bitMatrix.setRegion(9, 6, dimension - 17, 1);

            if (_versionNumber > 6)
            {
                // Version info, top right
                bitMatrix.setRegion(dimension - 11, 0, 3, 6);
                // Version info, bottom left
                bitMatrix.setRegion(0, dimension - 11, 6, 3);
            }

            return(bitMatrix);
        }
Exemple #22
0
        public Result Decode(BinaryBitmap image, System.Collections.Hashtable hints)
        {
            DecoderResult decoderResult;

            ResultPoint[] points;
            if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE))
            {
                BitMatrix bits = extractPureBits(image);
                decoderResult = decoder.decode(bits);
                points        = NO_POINTS;
            }
            else
            {
                DetectorResult detectorResult = new Detector(image).detect();
                decoderResult = decoder.decode(detectorResult.Bits);
                points        = detectorResult.Points;
            }
            return(new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.PDF417));
        }
Exemple #23
0
		/// <summary> <p>Decodes a PDF417 Code represented as a {@link BitMatrix}.
		/// A 1 or "true" is taken to mean a black module.</p>
		/// 
		/// </summary>
		/// <param name="bits">booleans representing white/black PDF417 Code modules
		/// </param>
		/// <returns> text and bytes encoded within the PDF417 Code
		/// </returns>
		/// <throws>  ReaderException if the PDF417 Code cannot be decoded </throws>
		public DecoderResult decode(BitMatrix bits)
		{
			// Construct a parser to read the data codewords and error-correction level
			BitMatrixParser parser = new BitMatrixParser(bits);
			int[] codewords = parser.readCodewords();
			if (codewords == null || codewords.Length == 0)
			{
				throw ReaderException.Instance;
			}
			
			int ecLevel = parser.ECLevel;
			int numECCodewords = 1 << (ecLevel + 1);
			int[] erasures = parser.Erasures;
			
			correctErrors(codewords, erasures, numECCodewords);
			verifyCodewordCount(codewords, numECCodewords);
			
			// Decode the codewords
			return DecodedBitStreamParser.decode(codewords);
		}
Exemple #24
0
        /// <summary> <p>Decodes a PDF417 Code represented as a {@link BitMatrix}.
        /// A 1 or "true" is taken to mean a black module.</p>
        ///
        /// </summary>
        /// <param name="bits">booleans representing white/black PDF417 Code modules
        /// </param>
        /// <returns> text and bytes encoded within the PDF417 Code
        /// </returns>
        /// <throws>  ReaderException if the PDF417 Code cannot be decoded </throws>
        public DecoderResult decode(BitMatrix bits)
        {
            // Construct a parser to read the data codewords and error-correction level
            BitMatrixParser parser = new BitMatrixParser(bits);

            int[] codewords = parser.readCodewords();
            if (codewords == null || codewords.Length == 0)
            {
                throw ReaderException.Instance;
            }

            int ecLevel        = parser.ECLevel;
            int numECCodewords = 1 << (ecLevel + 1);

            int[] erasures = parser.Erasures;

            correctErrors(codewords, erasures, numECCodewords);
            verifyCodewordCount(codewords, numECCodewords);

            // Decode the codewords
            return(DecodedBitStreamParser.decode(codewords));
        }
Exemple #25
0
        public DetectorResult[] detectMulti(System.Collections.Hashtable hints)
        {
            BitMatrix image = Image;
            MultiFinderPatternFinder finder = new MultiFinderPatternFinder(image);

            FinderPatternInfo[] info = finder.findMulti(hints);

            if (info == null || info.Length == 0)
            {
                throw ReaderException.Instance;
            }

            System.Collections.ArrayList result = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
            for (int i = 0; i < info.Length; i++)
            {
                try
                {
                    result.Add(ProcessFinderPatternInfo(info[i]));
                }
                catch (ReaderException)
                {
                    // ignore
                }
            }
            if ((result.Count == 0))
            {
                return(EMPTY_DETECTOR_RESULTS);
            }
            else
            {
                DetectorResult[] resultArray = new DetectorResult[result.Count];
                for (int i = 0; i < result.Count; i++)
                {
                    resultArray[i] = (DetectorResult)result[i];
                }
                return(resultArray);
            }
        }
Exemple #26
0
		/// <summary> <p>Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p>
		/// 
		/// </summary>
		/// <param name="bits">booleans representing white/black QR Code modules
		/// </param>
		/// <returns> text and bytes encoded within the QR Code
		/// </returns>
		/// <throws>  ReaderException if the QR Code cannot be decoded </throws>
		public DecoderResult decode(BitMatrix bits)
		{
			
			// Construct a parser and read version, error-correction level
			BitMatrixParser parser = new BitMatrixParser(bits);
			Version version = parser.readVersion();
			ErrorCorrectionLevel ecLevel = parser.readFormatInformation().ErrorCorrectionLevel;
			
			// Read codewords
			sbyte[] codewords = parser.readCodewords();
			// Separate into data blocks
			DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel);
			
			// Count total number of data bytes
			int totalBytes = 0;
			for (int i = 0; i < dataBlocks.Length; i++)
			{
				totalBytes += dataBlocks[i].NumDataCodewords;
			}
			sbyte[] resultBytes = new sbyte[totalBytes];
			int resultOffset = 0;
			
			// Error-correct and copy data blocks together into a stream of bytes
			for (int j = 0; j < dataBlocks.Length; j++)
			{
				DataBlock dataBlock = dataBlocks[j];
				sbyte[] codewordBytes = dataBlock.Codewords;
				int numDataCodewords = dataBlock.NumDataCodewords;
				correctErrors(codewordBytes, numDataCodewords);
				for (int i = 0; i < numDataCodewords; i++)
				{
					resultBytes[resultOffset++] = codewordBytes[i];
				}
			}
			
			// Decode the contents of that stream of bytes
			return DecodedBitStreamParser.decode(resultBytes, version, ecLevel);
		}
Exemple #27
0
        /// <summary> <p>Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p>
        ///
        /// </summary>
        /// <param name="bits">booleans representing white/black QR Code modules
        /// </param>
        /// <returns> text and bytes encoded within the QR Code
        /// </returns>
        /// <throws>  ReaderException if the QR Code cannot be decoded </throws>
        public DecoderResult decode(BitMatrix bits)
        {
            // Construct a parser and read version, error-correction level
            BitMatrixParser      parser  = new BitMatrixParser(bits);
            Version              version = parser.readVersion();
            ErrorCorrectionLevel ecLevel = parser.readFormatInformation().ErrorCorrectionLevel;

            // Read codewords
            sbyte[] codewords = parser.readCodewords();
            // Separate into data blocks
            DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel);

            // Count total number of data bytes
            int totalBytes = 0;

            for (int i = 0; i < dataBlocks.Length; i++)
            {
                totalBytes += dataBlocks[i].NumDataCodewords;
            }
            sbyte[] resultBytes  = new sbyte[totalBytes];
            int     resultOffset = 0;

            // Error-correct and copy data blocks together into a stream of bytes
            for (int j = 0; j < dataBlocks.Length; j++)
            {
                DataBlock dataBlock        = dataBlocks[j];
                sbyte[]   codewordBytes    = dataBlock.Codewords;
                int       numDataCodewords = dataBlock.NumDataCodewords;
                correctErrors(codewordBytes, numDataCodewords);
                for (int i = 0; i < numDataCodewords; i++)
                {
                    resultBytes[resultOffset++] = codewordBytes[i];
                }
            }

            // Decode the contents of that stream of bytes
            return(DecodedBitStreamParser.decode(resultBytes, version, ecLevel));
        }
Exemple #28
0
 public Detector(BitMatrix image)
 {
     this.image        = image;
     rectangleDetector = new MonochromeRectangleDetector(image);
 }
Exemple #29
0
		/// <summary>
		/// 
		/// </summary>
		/// <param name="image"></param>
		public Detector(BitMatrix image)
		{
			this._image = image;
		}
		/// <summary> 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.
		/// </summary>
		private static BitMatrix extractPureBits(BitMatrix image)
		{
			// Now need to determine module size in pixels
			
			int height = image.Height;
			int width = image.Width;
			int minDimension = System.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.get_Renamed(borderWidth, borderWidth))
			{
				borderWidth++;
			}
			if (borderWidth == minDimension)
			{
				throw ReaderException.Instance;
			}
			
			// And then keep tracking across the top-left black module to determine module size
			int moduleEnd = borderWidth + 1;
			while (moduleEnd < width && image.get_Renamed(moduleEnd, borderWidth))
			{
				moduleEnd++;
			}
			if (moduleEnd == width)
			{
				throw ReaderException.Instance;
			}
			
			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.get_Renamed(borderWidth, columnEndOfSymbol))
			{
				columnEndOfSymbol--;
			}
			if (columnEndOfSymbol < 0)
			{
				throw ReaderException.Instance;
			}
			columnEndOfSymbol++;
			
			// Make sure width of barcode is a multiple of module size
			if ((columnEndOfSymbol - borderWidth) % moduleSize != 0)
			{
				throw ReaderException.Instance;
			}
			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 ReaderException.Instance;
			}
			
			// 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.get_Renamed(borderWidth + j * moduleSize, iOffset))
					{
						bits.set_Renamed(j, i);
					}
				}
			}
			return bits;
		}
		/// <summary> <p>Creates a finder that will search the image for three finder patterns.</p>
		/// 
		/// </summary>
		/// <param name="image">image to search
		/// </param>
		public FinderPatternFinder(BitMatrix image):this(image, null)
		{
		}
		/// <summary> <p>Creates a finder that will search the image for three finder patterns.</p>
		/// 
		/// </summary>
		/// <param name="image">image to search
		/// </param>
		internal MultiFinderPatternFinder(BitMatrix image):base(image)
		{
		}
Exemple #33
0
		/// <param name="matrix">row of black/white values to search
		/// </param>
		/// <param name="column">x position to start search
		/// </param>
		/// <param name="row">y position to start search
		/// </param>
		/// <param name="width">the number of pixels to search on this row
		/// </param>
		/// <param name="pattern">pattern of counts of number of black and white pixels that are
		/// being searched for as a pattern
		/// </param>
		/// <returns> start/end horizontal offset of guard pattern, as an array of two ints.
		/// </returns>
		private static int[] findGuardPattern(BitMatrix matrix, int column, int row, int width, bool whiteFirst, int[] pattern)
		{
			int patternLength = pattern.Length;
			// TODO: Find a way to cache this array, as this method is called hundreds of times
			// per image, and we want to allocate as seldom as possible.
			int[] counters = new int[patternLength];
			bool isWhite = whiteFirst;
			
			int counterPosition = 0;
			int patternStart = column;
			for (int x = column; x < column + width; x++)
			{
				bool pixel = matrix.get_Renamed(x, row);
				if (pixel ^ isWhite)
				{
					counters[counterPosition]++;
				}
				else
				{
					if (counterPosition == patternLength - 1)
					{
						if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE)
						{
							return new int[]{patternStart, x};
						}
						patternStart += counters[0] + counters[1];
						for (int y = 2; y < patternLength; y++)
						{
							counters[y - 2] = counters[y];
						}
						counters[patternLength - 2] = 0;
						counters[patternLength - 1] = 0;
						counterPosition--;
					}
					else
					{
						counterPosition++;
					}
					counters[counterPosition] = 1;
					isWhite = !isWhite;
				}
			}
			return null;
		}
Exemple #34
0
		/// <summary> Locate the vertices and the codewords area of a black blob using the Start
		/// and Stop patterns as locators. This assumes that the image is rotated 180
		/// degrees and if it locates the start and stop patterns at it will re-map
		/// the vertices for a 0 degree rotation.
		/// TODO: Change assumption about barcode location.
		/// TODO: Scanning every row is very expensive. We should only do this for TRY_HARDER.
		/// 
		/// </summary>
		/// <param name="matrix">the scanned barcode image.
		/// </param>
		/// <returns> an array containing the vertices:
		/// vertices[0] x, y top left barcode
		/// vertices[1] x, y bottom left barcode
		/// vertices[2] x, y top right barcode
		/// vertices[3] x, y bottom right barcode
		/// vertices[4] x, y top left codeword area
		/// vertices[5] x, y bottom left codeword area
		/// vertices[6] x, y top right codeword area
		/// vertices[7] x, y bottom right codeword area
		/// </returns>
		private static ResultPoint[] findVertices180(BitMatrix matrix)
		{
			int height = matrix.Height;
			int width = matrix.Width;
			int halfWidth = width >> 1;
			
			ResultPoint[] result = new ResultPoint[8];
			bool found = false;
			
			// Top Left
			for (int i = height - 1; i > 0; i--)
			{
				int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE);
				if (loc != null)
				{
					result[0] = new ResultPoint(loc[1], i);
					result[4] = new ResultPoint(loc[0], i);
					found = true;
					break;
				}
			}
			// Bottom Left
			if (found)
			{
				// Found the Top Left vertex
				found = false;
				for (int i = 0; i < height; i++)
				{
					int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE);
					if (loc != null)
					{
						result[1] = new ResultPoint(loc[1], i);
						result[5] = new ResultPoint(loc[0], i);
						found = true;
						break;
					}
				}
			}
			// Top Right
			if (found)
			{
				// Found the Bottom Left vertex
				found = false;
				for (int i = height - 1; i > 0; i--)
				{
					int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE);
					if (loc != null)
					{
						result[2] = new ResultPoint(loc[0], i);
						result[6] = new ResultPoint(loc[1], i);
						found = true;
						break;
					}
				}
			}
			// Bottom Right
			if (found)
			{
				// Found the Top Right vertex
				found = false;
				for (int i = 0; i < height; i++)
				{
					int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE);
					if (loc != null)
					{
						result[3] = new ResultPoint(loc[0], i);
						result[7] = new ResultPoint(loc[1], i);
						found = true;
						break;
					}
				}
			}
			return found?result:null;
		}
        /// <summary> <p>After a horizontal scan finds a potential alignment pattern, this method
        /// "cross-checks" by scanning down vertically through the center of the possible
        /// alignment pattern to see if the same proportion is detected.</p>
        ///
        /// </summary>
        /// <param name="startI">row where an alignment pattern was detected
        /// </param>
        /// <param name="centerJ">center of the section that appears to cross an alignment pattern
        /// </param>
        /// <param name="maxCount">maximum reasonable number of modules that should be
        /// observed in any reading state, based on the results of the horizontal scan
        /// </param>
        /// <returns> vertical center of alignment pattern, or {@link Float#NaN} if not found
        /// </returns>
        private float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal)
        {
            BitMatrix image = this.image;

            int maxI = image.Height;

            int[] stateCount = crossCheckStateCount;
            stateCount[0] = 0;
            stateCount[1] = 0;
            stateCount[2] = 0;

            // Start counting up from center
            int i = startI;

            while (i >= 0 && image.get_Renamed(centerJ, i) && stateCount[1] <= maxCount)
            {
                stateCount[1]++;
                i--;
            }
            // If already too many modules in this state or ran off the edge:
            if (i < 0 || stateCount[1] > maxCount)
            {
                return(System.Single.NaN);
            }
            while (i >= 0 && !image.get_Renamed(centerJ, i) && stateCount[0] <= maxCount)
            {
                stateCount[0]++;
                i--;
            }
            if (stateCount[0] > maxCount)
            {
                return(System.Single.NaN);
            }

            // Now also count down from center
            i = startI + 1;
            while (i < maxI && image.get_Renamed(centerJ, i) && stateCount[1] <= maxCount)
            {
                stateCount[1]++;
                i++;
            }
            if (i == maxI || stateCount[1] > maxCount)
            {
                return(System.Single.NaN);
            }
            while (i < maxI && !image.get_Renamed(centerJ, i) && stateCount[2] <= maxCount)
            {
                stateCount[2]++;
                i++;
            }
            if (stateCount[2] > maxCount)
            {
                return(System.Single.NaN);
            }

            int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];

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

            return(foundPatternCross(stateCount)?centerFromEnd(stateCount, i):System.Single.NaN);
        }
Exemple #36
0
        /// <summary> <p>Reads the bits in the {@link BitMatrix} representing the finder pattern in the
        /// correct order in order to reconstitute the codewords bytes contained within the
        /// QR Code.</p>
        ///
        /// </summary>
        /// <returns> bytes encoded within the QR Code
        /// </returns>
        /// <throws>  ReaderException if the exact number of bytes expected is not read </throws>
        internal sbyte[] readCodewords()
        {
            FormatInformation formatInfo = readFormatInformation();
            Version           version    = readVersion();

            // Get the data mask for the format used in this QR Code. This will exclude
            // some bits from reading as we wind through the bit matrix.
            DataMask dataMask  = DataMask.forReference((int)formatInfo.DataMask);
            int      dimension = bitMatrix.Dimension;

            dataMask.unmaskBitMatrix(bitMatrix, dimension);

            BitMatrix functionPattern = version.buildFunctionPattern();

            bool readingUp = true;

            sbyte[] result       = new sbyte[version.TotalCodewords];
            int     resultOffset = 0;
            int     currentByte  = 0;
            int     bitsRead     = 0;

            // Read columns in pairs, from right to left
            for (int j = dimension - 1; j > 0; j -= 2)
            {
                if (j == 6)
                {
                    // Skip whole column with vertical alignment pattern;
                    // saves time and makes the other code proceed more cleanly
                    j--;
                }
                // Read alternatingly from bottom to top then top to bottom
                for (int count = 0; count < dimension; count++)
                {
                    int i = readingUp?dimension - 1 - count:count;
                    for (int col = 0; col < 2; col++)
                    {
                        // Ignore bits covered by the function pattern
                        if (!functionPattern.get_Renamed(j - col, i))
                        {
                            // Read a bit
                            bitsRead++;
                            currentByte <<= 1;
                            if (bitMatrix.get_Renamed(j - col, i))
                            {
                                currentByte |= 1;
                            }
                            // If we've made a whole byte, save it off
                            if (bitsRead == 8)
                            {
                                result[resultOffset++] = (sbyte)currentByte;
                                bitsRead    = 0;
                                currentByte = 0;
                            }
                        }
                    }
                }
                readingUp ^= true;                 // readingUp = !readingUp; // switch directions
            }
            if (resultOffset != version.TotalCodewords)
            {
                throw ReaderException.Instance;
            }
            return(result);
        }
Exemple #37
0
        /// <summary> <p>After a horizontal scan finds a potential finder pattern, this method
        /// "cross-checks" by scanning down vertically through the center of the possible
        /// finder pattern to see if the same proportion is detected.</p>
        ///
        /// </summary>
        /// <param name="startI">row where a finder pattern was detected
        /// </param>
        /// <param name="centerJ">center of the section that appears to cross a finder pattern
        /// </param>
        /// <param name="maxCount">maximum reasonable number of modules that should be
        /// observed in any reading state, based on the results of the horizontal scan
        /// </param>
        /// <returns> vertical center of finder pattern, or {@link Float#NaN} if not found
        /// </returns>
        private float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal)
        {
            BitMatrix image = this.image;

            int maxI = image.Height;

            int[] stateCount = CrossCheckStateCount;

            // Start counting up from center
            int i = startI;

            while (i >= 0 && image.get_Renamed(centerJ, i))
            {
                stateCount[2]++;
                i--;
            }
            if (i < 0)
            {
                return(System.Single.NaN);
            }
            while (i >= 0 && !image.get_Renamed(centerJ, i) && stateCount[1] <= maxCount)
            {
                stateCount[1]++;
                i--;
            }
            // If already too many modules in this state or ran off the edge:
            if (i < 0 || stateCount[1] > maxCount)
            {
                return(System.Single.NaN);
            }
            while (i >= 0 && image.get_Renamed(centerJ, i) && stateCount[0] <= maxCount)
            {
                stateCount[0]++;
                i--;
            }
            if (stateCount[0] > maxCount)
            {
                return(System.Single.NaN);
            }

            // Now also count down from center
            i = startI + 1;
            while (i < maxI && image.get_Renamed(centerJ, i))
            {
                stateCount[2]++;
                i++;
            }
            if (i == maxI)
            {
                return(System.Single.NaN);
            }
            while (i < maxI && !image.get_Renamed(centerJ, i) && stateCount[3] < maxCount)
            {
                stateCount[3]++;
                i++;
            }
            if (i == maxI || stateCount[3] >= maxCount)
            {
                return(System.Single.NaN);
            }
            while (i < maxI && image.get_Renamed(centerJ, i) && stateCount[4] < maxCount)
            {
                stateCount[4]++;
                i++;
            }
            if (stateCount[4] >= maxCount)
            {
                return(System.Single.NaN);
            }

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

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

            return(foundPatternCross(stateCount)?centerFromEnd(stateCount, i):System.Single.NaN);
        }
Exemple #38
0
        /// <summary> <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>
        /// </summary>
        private float crossCheckHorizontal(int startJ, int centerI, int maxCount, int originalStateCountTotal)
        {
            BitMatrix image = this.image;

            int maxJ = image.Width;

            int[] stateCount = CrossCheckStateCount;

            int j = startJ;

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

            j = startJ + 1;
            while (j < maxJ && image.get_Renamed(j, centerI))
            {
                stateCount[2]++;
                j++;
            }
            if (j == maxJ)
            {
                return(System.Single.NaN);
            }
            while (j < maxJ && !image.get_Renamed(j, centerI) && stateCount[3] < maxCount)
            {
                stateCount[3]++;
                j++;
            }
            if (j == maxJ || stateCount[3] >= maxCount)
            {
                return(System.Single.NaN);
            }
            while (j < maxJ && image.get_Renamed(j, centerI) && stateCount[4] < maxCount)
            {
                stateCount[4]++;
                j++;
            }
            if (stateCount[4] >= maxCount)
            {
                return(System.Single.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 * System.Math.Abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal)
            {
                return(System.Single.NaN);
            }

            return(foundPatternCross(stateCount)?centerFromEnd(stateCount, j):System.Single.NaN);
        }
Exemple #39
0
        /// <summary> Locate the vertices and the codewords area of a black blob using the Start
        /// and Stop patterns as locators. This assumes that the image is rotated 180
        /// degrees and if it locates the start and stop patterns at it will re-map
        /// the vertices for a 0 degree rotation.
        /// TODO: Change assumption about barcode location.
        /// TODO: Scanning every row is very expensive. We should only do this for TRY_HARDER.
        ///
        /// </summary>
        /// <param name="matrix">the scanned barcode image.
        /// </param>
        /// <returns> an array containing the vertices:
        /// vertices[0] x, y top left barcode
        /// vertices[1] x, y bottom left barcode
        /// vertices[2] x, y top right barcode
        /// vertices[3] x, y bottom right barcode
        /// vertices[4] x, y top left codeword area
        /// vertices[5] x, y bottom left codeword area
        /// vertices[6] x, y top right codeword area
        /// vertices[7] x, y bottom right codeword area
        /// </returns>
        private static ResultPoint[] findVertices180(BitMatrix matrix)
        {
            int height    = matrix.Height;
            int width     = matrix.Width;
            int halfWidth = width >> 1;

            ResultPoint[] result = new ResultPoint[8];
            bool          found  = false;

            // Top Left
            for (int i = height - 1; i > 0; i--)
            {
                int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE);
                if (loc != null)
                {
                    result[0] = new ResultPoint(loc[1], i);
                    result[4] = new ResultPoint(loc[0], i);
                    found     = true;
                    break;
                }
            }
            // Bottom Left
            if (found)
            {
                // Found the Top Left vertex
                found = false;
                for (int i = 0; i < height; i++)
                {
                    int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE);
                    if (loc != null)
                    {
                        result[1] = new ResultPoint(loc[1], i);
                        result[5] = new ResultPoint(loc[0], i);
                        found     = true;
                        break;
                    }
                }
            }
            // Top Right
            if (found)
            {
                // Found the Bottom Left vertex
                found = false;
                for (int i = height - 1; i > 0; i--)
                {
                    int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE);
                    if (loc != null)
                    {
                        result[2] = new ResultPoint(loc[0], i);
                        result[6] = new ResultPoint(loc[1], i);
                        found     = true;
                        break;
                    }
                }
            }
            // Bottom Right
            if (found)
            {
                // Found the Top Right vertex
                found = false;
                for (int i = 0; i < height; i++)
                {
                    int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE);
                    if (loc != null)
                    {
                        result[3] = new ResultPoint(loc[0], i);
                        result[7] = new ResultPoint(loc[1], i);
                        found     = true;
                        break;
                    }
                }
            }
            return(found?result:null);
        }
Exemple #40
0
 /// <summary> <p>Creates a finder that will search the image for three finder patterns.</p>
 ///
 /// </summary>
 /// <param name="image">image to search
 /// </param>
 public FinderPatternFinder(BitMatrix image) : this(image, null)
 {
 }
Exemple #41
0
        /// <summary> <p>Detects a Data Matrix Code in an image.</p>
        ///
        /// </summary>
        /// <returns> {@link DetectorResult} encapsulating results of detecting a QR Code
        /// </returns>
        /// <throws>  ReaderException if no Data Matrix Code can be found </throws>
        public DetectorResult detect()
        {
            ResultPoint[] cornerPoints = rectangleDetector.detect();
            ResultPoint   pointA       = cornerPoints[0];
            ResultPoint   pointB       = cornerPoints[1];
            ResultPoint   pointC       = cornerPoints[2];
            ResultPoint   pointD       = cornerPoints[3];

            // Point A and D are across the diagonal from one another,
            // as are B and C. Figure out which are the solid black lines
            // by counting transitions
            System.Collections.ArrayList transitions = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(4));
            transitions.Add(transitionsBetween(pointA, pointB));
            transitions.Add(transitionsBetween(pointA, pointC));
            transitions.Add(transitionsBetween(pointB, pointD));
            transitions.Add(transitionsBetween(pointC, pointD));
            Collections.insertionSort(transitions, new ResultPointsAndTransitionsComparator());

            // Sort by number of transitions. First two will be the two solid sides; last two
            // will be the two alternating black/white sides
            ResultPointsAndTransitions lSideOne = (ResultPointsAndTransitions)transitions[0];
            ResultPointsAndTransitions lSideTwo = (ResultPointsAndTransitions)transitions[1];

            // Figure out which point is their intersection by tallying up the number of times we see the
            // endpoints in the four endpoints. One will show up twice.
            System.Collections.Hashtable pointCount = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());
            increment(pointCount, lSideOne.From);
            increment(pointCount, lSideOne.To);
            increment(pointCount, lSideTwo.From);
            increment(pointCount, lSideTwo.To);

            ResultPoint maybeTopLeft     = null;
            ResultPoint bottomLeft       = null;
            ResultPoint maybeBottomRight = null;

            System.Collections.IEnumerator points = pointCount.Keys.GetEnumerator();
            //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"
            while (points.MoveNext())
            {
                //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"
                ResultPoint  point         = (ResultPoint)points.Current;
                System.Int32 value_Renamed = (System.Int32)pointCount[point];
                if (value_Renamed == 2)
                {
                    bottomLeft = point;                     // this is definitely the bottom left, then -- end of two L sides
                }
                else
                {
                    // Otherwise it's either top left or bottom right -- just assign the two arbitrarily now
                    if (maybeTopLeft == null)
                    {
                        maybeTopLeft = point;
                    }
                    else
                    {
                        maybeBottomRight = point;
                    }
                }
            }

            if (maybeTopLeft == null || bottomLeft == null || maybeBottomRight == null)
            {
                throw ReaderException.Instance;
            }

            // Bottom left is correct but top left and bottom right might be switched
            ResultPoint[] corners = new ResultPoint[] { maybeTopLeft, bottomLeft, maybeBottomRight };
            // Use the dot product trick to sort them out
            ResultPoint.orderBestPatterns(corners);

            // Now we know which is which:
            ResultPoint bottomRight = corners[0];

            bottomLeft = corners[1];
            ResultPoint topLeft = corners[2];

            // Which point didn't we find in relation to the "L" sides? that's the top right corner
            ResultPoint topRight;

            if (!pointCount.ContainsKey(pointA))
            {
                topRight = pointA;
            }
            else if (!pointCount.ContainsKey(pointB))
            {
                topRight = pointB;
            }
            else if (!pointCount.ContainsKey(pointC))
            {
                topRight = pointC;
            }
            else
            {
                topRight = pointD;
            }

            // Next determine the dimension by tracing along the top or right side and counting black/white
            // transitions. Since we start inside a black module, we should see a number of transitions
            // equal to 1 less than the code dimension. Well, actually 2 less, because we are going to
            // end on a black module:

            // The top right point is actually the corner of a module, which is one of the two black modules
            // adjacent to the white module at the top right. Tracing to that corner from either the top left
            // or bottom right should work here. The number of transitions could be higher than it should be
            // due to noise. So we try both and take the min.

            int dimension = System.Math.Min(transitionsBetween(topLeft, topRight).Transitions, transitionsBetween(bottomRight, topRight).Transitions);

            if ((dimension & 0x01) == 1)
            {
                // it can't be odd, so, round... up?
                dimension++;
            }
            dimension += 2;

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

            return(new DetectorResult(bits, new ResultPoint[] { pointA, pointB, pointC, pointD }));
        }
Exemple #42
0
		/// <summary> See ISO 18004:2006 Annex E</summary>
		internal BitMatrix buildFunctionPattern()
		{
			int dimension = DimensionForVersion;
			BitMatrix bitMatrix = new BitMatrix(dimension);
			
			// Top left finder pattern + separator + format
			bitMatrix.setRegion(0, 0, 9, 9);
			// Top right finder pattern + separator + format
			bitMatrix.setRegion(dimension - 8, 0, 8, 9);
			// Bottom left finder pattern + separator + format
			bitMatrix.setRegion(0, dimension - 8, 9, 8);
			
			// Alignment patterns
			int max = _alignmentPatternCenters.Length;
			for (int x = 0; x < max; x++)
			{
				int i = _alignmentPatternCenters[x] - 2;
				for (int y = 0; y < max; y++)
				{
					if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0))
					{
						// No alignment patterns near the three finder paterns
						continue;
					}
					bitMatrix.setRegion(_alignmentPatternCenters[y] - 2, i, 5, 5);
				}
			}
			
			// Vertical timing pattern
			bitMatrix.setRegion(6, 9, 1, dimension - 17);
			// Horizontal timing pattern
			bitMatrix.setRegion(9, 6, dimension - 17, 1);
			
			if (_versionNumber > 6)
			{
				// Version info, top right
				bitMatrix.setRegion(dimension - 11, 0, 3, 6);
				// Version info, bottom left
				bitMatrix.setRegion(0, dimension - 11, 6, 3);
			}
			
			return bitMatrix;
		}
		/// <summary> This method detects a barcode in a "pure" image -- that is, pure monochrome image
		/// which contains only an unrotated, unskewed, image of a barcode, with some white border
		/// around it. This is a specialized method that works exceptionally fast in this special
		/// case.
		/// </summary>
		private static BitMatrix extractPureBits(BinaryBitmap image)
		{
			// Now need to determine module size in pixels
			BitMatrix matrix = image.BlackMatrix;
			int height = matrix.Height;
			int width = matrix.Width;
			int minDimension = System.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 && !matrix.get_Renamed(borderWidth, borderWidth))
			{
				borderWidth++;
			}
			if (borderWidth == minDimension)
			{
				throw ReaderException.Instance;
			}
			
			// And then keep tracking across the top-left black module to determine module size
			int moduleEnd = borderWidth;
			while (moduleEnd < minDimension && matrix.get_Renamed(moduleEnd, moduleEnd))
			{
				moduleEnd++;
			}
			if (moduleEnd == minDimension)
			{
				throw ReaderException.Instance;
			}
			
			int moduleSize = moduleEnd - borderWidth;
			
			// And now find where the rightmost black module on the first row ends
			int rowEndOfSymbol = width - 1;
			while (rowEndOfSymbol >= 0 && !matrix.get_Renamed(rowEndOfSymbol, borderWidth))
			{
				rowEndOfSymbol--;
			}
			if (rowEndOfSymbol < 0)
			{
				throw ReaderException.Instance;
			}
			rowEndOfSymbol++;
			
			// Make sure width of barcode is a multiple of module size
			if ((rowEndOfSymbol - borderWidth) % moduleSize != 0)
			{
				throw ReaderException.Instance;
			}
			int dimension = (rowEndOfSymbol - 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 ReaderException.Instance;
			}
			
			// Now just read off the bits
			BitMatrix bits = new BitMatrix(dimension);
			for (int y = 0; y < dimension; y++)
			{
				int iOffset = borderWidth + y * moduleSize;
				for (int x = 0; x < dimension; x++)
				{
					if (matrix.get_Renamed(borderWidth + x * moduleSize, iOffset))
					{
						bits.set_Renamed(x, y);
					}
				}
			}
			return bits;
		}
Exemple #44
0
		private static BitMatrix sampleGrid(BitMatrix matrix, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, ResultPoint bottomRight, int dimension)
		{
			
			// Note that unlike the QR Code sampler, we didn't find the center of modules, but the
			// very corners. So there is no 0.5f here; 0.0f is right.
			GridSampler sampler = GridSampler.Instance;
			
			return sampler.sampleGrid(matrix, dimension, 0.0f, 0.0f, dimension, 0.0f, dimension, dimension, 0.0f, dimension, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y); // p4FromY
		}
		public MultiDetector(BitMatrix image):base(image)
		{
		}
		public FinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback)
		{
			this.image = image;
			this.possibleCenters = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
			this.crossCheckStateCount = new int[5];
			this.resultPointCallback = resultPointCallback;
		}
		internal BitMatrixParser(BitMatrix bitMatrix)
		{
			this.bitMatrix = bitMatrix;
		}
		internal MultiFinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback):base(image, resultPointCallback)
		{
		}
Exemple #49
0
		public Detector(BitMatrix image)
		{
			this.image = image;
			rectangleDetector = new MonochromeRectangleDetector(image);
		}
		/// <summary> <p>Extracts the data region from a {@link BitMatrix} that contains
		/// alignment patterns.</p>
		/// 
		/// </summary>
		/// <param name="bitMatrix">Original {@link BitMatrix} with alignment patterns
		/// </param>
		/// <returns> BitMatrix that has the alignment patterns removed
		/// </returns>
		internal BitMatrix extractDataRegion(BitMatrix bitMatrix)
		{
			int symbolSizeRows = version.SymbolSizeRows;
			int symbolSizeColumns = version.SymbolSizeColumns;
			
			// TODO(bbrown): Make this work with rectangular codes
			if (bitMatrix.Dimension != symbolSizeRows)
			{
				throw new System.ArgumentException("Dimension of bitMarix must match the version size");
			}
			
			int dataRegionSizeRows = version.DataRegionSizeRows;
			int dataRegionSizeColumns = version.DataRegionSizeColumns;
			
			int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows;
			int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;
			
			int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;
			//int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;
			
			// TODO(bbrown): Make this work with rectangular codes
			BitMatrix bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionRow);
			for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow)
			{
				int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;
				for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn)
				{
					int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns;
					for (int i = 0; i < dataRegionSizeRows; ++i)
					{
						int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;
						int writeRowOffset = dataRegionRowOffset + i;
						for (int j = 0; j < dataRegionSizeColumns; ++j)
						{
							int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;
							if (bitMatrix.get_Renamed(readColumnOffset, readRowOffset))
							{
								int writeColumnOffset = dataRegionColumnOffset + j;
								bitMatrixWithoutAlignment.set_Renamed(writeColumnOffset, writeRowOffset);
							}
						}
					}
				}
			}
			return bitMatrixWithoutAlignment;
		}
Exemple #51
0
		private static BitMatrix sampleGrid(BitMatrix image, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint bottomRight, int dimension)
		{
			
			// We make up the top right point for now, based on the others.
			// TODO: we actually found a fourth corner above and figured out which of two modules
			// it was the corner of. We could use that here and adjust for perspective distortion.
			float topRightX = (bottomRight.X - bottomLeft.X) + topLeft.X;
			float topRightY = (bottomRight.Y - bottomLeft.Y) + topLeft.Y;
			
			// Note that unlike in the QR Code sampler, we didn't find the center of modules, but the
			// very corners. So there is no 0.5f here; 0.0f is right.
			GridSampler sampler = GridSampler.Instance;
			return sampler.sampleGrid(image, dimension, 0.0f, 0.0f, dimension, 0.0f, dimension, dimension, 0.0f, dimension, topLeft.X, topLeft.Y, topRightX, topRightY, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y);
		}
Exemple #52
0
        private static BitMatrix sampleGrid(BitMatrix image, PerspectiveTransform transform, int dimension)
        {
            GridSampler sampler = GridSampler.Instance;

            return(sampler.sampleGrid(image, dimension, transform));
        }
Exemple #53
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="image"></param>
 public Detector(BitMatrix image)
 {
     this._image = image;
 }
Exemple #54
0
        /// <summary> This method detects a barcode in a "pure" image -- that is, pure monochrome image
        /// which contains only an unrotated, unskewed, image of a barcode, with some white border
        /// around it. This is a specialized method that works exceptionally fast in this special
        /// case.
        /// </summary>
        private static BitMatrix extractPureBits(BitMatrix image)
        {
            // Now need to determine module size in pixels

            int height       = image.Height;
            int width        = image.Width;
            int minDimension = System.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.get_Renamed(borderWidth, borderWidth))
            {
                borderWidth++;
            }
            if (borderWidth == minDimension)
            {
                throw ReaderException.Instance;
            }

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

            while (moduleEnd < minDimension && image.get_Renamed(moduleEnd, moduleEnd))
            {
                moduleEnd++;
            }
            if (moduleEnd == minDimension)
            {
                throw ReaderException.Instance;
            }

            int moduleSize = moduleEnd - borderWidth;

            // And now find where the rightmost black module on the first row ends
            int rowEndOfSymbol = width - 1;

            while (rowEndOfSymbol >= 0 && !image.get_Renamed(rowEndOfSymbol, borderWidth))
            {
                rowEndOfSymbol--;
            }
            if (rowEndOfSymbol < 0)
            {
                throw ReaderException.Instance;
            }
            rowEndOfSymbol++;

            // Make sure width of barcode is a multiple of module size
            if ((rowEndOfSymbol - borderWidth) % moduleSize != 0)
            {
                throw ReaderException.Instance;
            }
            int dimension = (rowEndOfSymbol - 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 ReaderException.Instance;
            }

            // 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.get_Renamed(borderWidth + j * moduleSize, iOffset))
                    {
                        bits.set_Renamed(j, i);
                    }
                }
            }
            return(bits);
        }
Exemple #55
0
		private static BitMatrix sampleGrid(BitMatrix image, PerspectiveTransform transform, int dimension)
		{
			
			GridSampler sampler = GridSampler.Instance;
			return sampler.sampleGrid(image, dimension, transform);
		}