예제 #1
0
 /// <summary> <p>Reads a bit of the mapping matrix accounting for boundary wrapping.</p>
 ///
 /// </summary>
 /// <param name="row">Row to read in the mapping matrix
 /// </param>
 /// <param name="column">Column to read in the mapping matrix
 /// </param>
 /// <param name="numRows">Number of rows in the mapping matrix
 /// </param>
 /// <param name="numColumns">Number of columns in the mapping matrix
 /// </param>
 /// <returns> value of the given bit in the mapping matrix
 /// </returns>
 internal bool readModule(int row, int column, int numRows, int numColumns)
 {
     // Adjust the row and column indices based on boundary wrapping
     if (row < 0)
     {
         row    += numRows;
         column += 4 - ((numRows + 4) & 0x07);
     }
     if (column < 0)
     {
         column += numColumns;
         row    += 4 - ((numColumns + 4) & 0x07);
     }
     readMappingMatrix.set_Renamed(column, row);
     return(mappingBitMatrix.get_Renamed(column, row));
 }
예제 #2
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);
        }
예제 #3
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);
        }
예제 #4
0
        /// <summary> <p>This method traces a line from a point in the image, in the direction towards another point.
        /// It begins in a black region, and keeps going until it finds white, then black, then white again.
        /// It reports the distance from the start to this point.</p>
        ///
        /// <p>This is used when figuring out how wide a finder pattern is, when the finder pattern
        /// may be skewed or rotated.</p>
        /// </summary>
        private float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY)
        {
            // Mild variant of Bresenham's algorithm;
            // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
            bool steep = System.Math.Abs(toY - fromY) > System.Math.Abs(toX - fromX);

            if (steep)
            {
                int temp = fromX;
                fromX = fromY;
                fromY = temp;
                temp  = toX;
                toX   = toY;
                toY   = temp;
            }

            int dx    = System.Math.Abs(toX - fromX);
            int dy    = System.Math.Abs(toY - fromY);
            int error = -dx >> 1;
            int ystep = fromY < toY?1:-1;
            int xstep = fromX < toX?1:-1;
            int state = 0;             // In black pixels, looking for white, first or second time

            for (int x = fromX, y = fromY; x != toX; x += xstep)
            {
                int realX = steep?y:x;
                int realY = steep?x:y;
                if (state == 1)
                {
                    // In white pixels, looking for black
                    if (_image.get_Renamed(realX, realY))
                    {
                        state++;
                    }
                }
                else
                {
                    if (!_image.get_Renamed(realX, realY))
                    {
                        state++;
                    }
                }

                if (state == 3)
                {
                    // Found black, white, black, and stumbled back onto white; done
                    int diffX = x - fromX;
                    int diffY = y - fromY;
                    //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'"
                    return((float)System.Math.Sqrt(diffX * diffX + diffY * diffY));
                }
                error += dy;
                if (error > 0)
                {
                    if (y == toY)
                    {
                        break;
                    }
                    y     += ystep;
                    error -= dx;
                }
            }
            int diffX2 = toX - fromX;
            int diffY2 = toY - fromY;

            //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'"
            return((float)System.Math.Sqrt(diffX2 * diffX2 + diffY2 * diffY2));
        }
예제 #5
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;
		}
예제 #6
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;
		}
예제 #7
0
        /// <summary> <p>This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since
        /// it's pretty performance-critical and so is written to be fast foremost.</p>
        ///
        /// </summary>
        /// <returns> {@link AlignmentPattern} if found
        /// </returns>
        /// <throws>  ReaderException if not found </throws>
        internal AlignmentPattern find()
        {
            int startX  = this.startX;
            int height  = this.height;
            int maxJ    = startX + width;
            int middleI = startY + (height >> 1);

            // We are looking for black/white/black modules in 1:1:1 ratio;
            // this tracks the number of black/white/black modules seen so far
            int[] stateCount = new int[3];
            for (int iGen = 0; iGen < height; iGen++)
            {
                // Search from middle outwards
                int i = middleI + ((iGen & 0x01) == 0?((iGen + 1) >> 1):-((iGen + 1) >> 1));
                stateCount[0] = 0;
                stateCount[1] = 0;
                stateCount[2] = 0;
                int j = startX;
                // Burn off leading white pixels before anything else; if we start in the middle of
                // a white run, it doesn't make sense to count its length, since we don't know if the
                // white run continued to the left of the start point
                while (j < maxJ && !image.get_Renamed(j, i))
                {
                    j++;
                }
                int currentState = 0;
                while (j < maxJ)
                {
                    if (image.get_Renamed(j, i))
                    {
                        // Black pixel
                        if (currentState == 1)
                        {
                            // Counting black pixels
                            stateCount[currentState]++;
                        }
                        else
                        {
                            // Counting white pixels
                            if (currentState == 2)
                            {
                                // A winner?
                                if (foundPatternCross(stateCount))
                                {
                                    // Yes
                                    AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, j);
                                    if (confirmed != null)
                                    {
                                        return(confirmed);
                                    }
                                }
                                stateCount[0] = stateCount[2];
                                stateCount[1] = 1;
                                stateCount[2] = 0;
                                currentState  = 1;
                            }
                            else
                            {
                                stateCount[++currentState]++;
                            }
                        }
                    }
                    else
                    {
                        // White pixel
                        if (currentState == 1)
                        {
                            // Counting black pixels
                            currentState++;
                        }
                        stateCount[currentState]++;
                    }
                    j++;
                }
                if (foundPatternCross(stateCount))
                {
                    AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, maxJ);
                    if (confirmed != null)
                    {
                        return(confirmed);
                    }
                }
            }

            // Hmm, nothing we saw was observed and confirmed twice. If we had
            // any guess at all, return it.
            if (!(possibleCenters.Count == 0))
            {
                return((AlignmentPattern)possibleCenters[0]);
            }

            throw ReaderException.Instance;
        }
예제 #8
0
        /// <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);
        }
예제 #9
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);
        }
예제 #10
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);
        }
예제 #11
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);
        }
예제 #12
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);
        }
예제 #13
0
 private int copyBit(int i, int j, int versionBits)
 {
     return(bitMatrix.get_Renamed(i, j)?(versionBits << 1) | 0x1:versionBits << 1);
 }
        public FinderPatternInfo[] findMulti(System.Collections.Hashtable hints)
        {
            bool      tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER);
            BitMatrix image     = Image;
            int       maxI      = image.Height;
            int       maxJ      = image.Width;
            // We are looking for black/white/black/white/black modules in
            // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far

            // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the
            // image, and then account for the center being 3 modules in size. This gives the smallest
            // number of pixels the center could be, so skip this often. When trying harder, look for all
            // QR versions regardless of how dense they are.
            //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 iSkip = (int)(maxI / (MAX_MODULES * 4.0f) * 3);

            if (iSkip < MIN_SKIP || tryHarder)
            {
                iSkip = MIN_SKIP;
            }

            int[] stateCount = new int[5];
            for (int i = iSkip - 1; i < maxI; i += iSkip)
            {
                // Get a row of black/white values
                stateCount[0] = 0;
                stateCount[1] = 0;
                stateCount[2] = 0;
                stateCount[3] = 0;
                stateCount[4] = 0;
                int currentState = 0;
                for (int j = 0; j < maxJ; j++)
                {
                    if (image.get_Renamed(j, i))
                    {
                        // Black pixel
                        if ((currentState & 1) == 1)
                        {
                            // Counting white pixels
                            currentState++;
                        }
                        stateCount[currentState]++;
                    }
                    else
                    {
                        // White pixel
                        if ((currentState & 1) == 0)
                        {
                            // Counting black pixels
                            if (currentState == 4)
                            {
                                // A winner?
                                if (foundPatternCross(stateCount))
                                {
                                    // Yes
                                    bool confirmed = handlePossibleCenter(stateCount, i, j);
                                    if (!confirmed)
                                    {
                                        do
                                        {
                                            // Advance to next black pixel
                                            j++;
                                        }while (j < maxJ && !image.get_Renamed(j, i));
                                        j--;                                         // back up to that last white pixel
                                    }
                                    // Clear state to start looking again
                                    currentState  = 0;
                                    stateCount[0] = 0;
                                    stateCount[1] = 0;
                                    stateCount[2] = 0;
                                    stateCount[3] = 0;
                                    stateCount[4] = 0;
                                }
                                else
                                {
                                    // No, shift counts back by two
                                    stateCount[0] = stateCount[2];
                                    stateCount[1] = stateCount[3];
                                    stateCount[2] = stateCount[4];
                                    stateCount[3] = 1;
                                    stateCount[4] = 0;
                                    currentState  = 3;
                                }
                            }
                            else
                            {
                                stateCount[++currentState]++;
                            }
                        }
                        else
                        {
                            // Counting white pixels
                            stateCount[currentState]++;
                        }
                    }
                }                 // for j=...

                if (foundPatternCross(stateCount))
                {
                    handlePossibleCenter(stateCount, i, maxJ);
                }         // end if foundPatternCross
            }             // for i=iSkip-1 ...
            FinderPattern[][]            patternInfo = selectBestPatterns();
            System.Collections.ArrayList result      = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
            for (int i = 0; i < patternInfo.Length; i++)
            {
                FinderPattern[] pattern = patternInfo[i];
                ResultPoint.orderBestPatterns(pattern);
                result.Add(new FinderPatternInfo(pattern));
            }

            if ((result.Count == 0))
            {
                return(EMPTY_RESULT_ARRAY);
            }
            else
            {
                FinderPatternInfo[] resultArray = new FinderPatternInfo[result.Count];
                for (int i = 0; i < result.Count; i++)
                {
                    resultArray[i] = (FinderPatternInfo)result[i];
                }
                return(resultArray);
            }
        }
예제 #15
0
        /// <summary> <p>Reads the bits in the {@link BitMatrix} representing the mapping matrix (No alignment patterns)
        /// in the correct order in order to reconstitute the codewords bytes contained within the
        /// Data Matrix Code.</p>
        ///
        /// </summary>
        /// <returns> bytes encoded within the Data Matrix Code
        /// </returns>
        /// <throws>  ReaderException if the exact number of bytes expected is not read </throws>
        internal sbyte[] readCodewords()
        {
            sbyte[] result       = new sbyte[version.TotalCodewords];
            int     resultOffset = 0;

            int row    = 4;
            int column = 0;
            // TODO(bbrown): Data Matrix can be rectangular, assuming square for now
            int numRows    = mappingBitMatrix.Dimension;
            int numColumns = numRows;

            bool corner1Read = false;
            bool corner2Read = false;
            bool corner3Read = false;
            bool corner4Read = false;

            // Read all of the codewords
            do
            {
                // Check the four corner cases
                if ((row == numRows) && (column == 0) && !corner1Read)
                {
                    result[resultOffset++] = (sbyte)readCorner1(numRows, numColumns);
                    row        -= 2;
                    column     += 2;
                    corner1Read = true;
                }
                else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read)
                {
                    result[resultOffset++] = (sbyte)readCorner2(numRows, numColumns);
                    row        -= 2;
                    column     += 2;
                    corner2Read = true;
                }
                else if ((row == numRows + 4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read)
                {
                    result[resultOffset++] = (sbyte)readCorner3(numRows, numColumns);
                    row        -= 2;
                    column     += 2;
                    corner3Read = true;
                }
                else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read)
                {
                    result[resultOffset++] = (sbyte)readCorner4(numRows, numColumns);
                    row        -= 2;
                    column     += 2;
                    corner4Read = true;
                }
                else
                {
                    // Sweep upward diagonally to the right
                    do
                    {
                        if ((row < numRows) && (column >= 0) && !readMappingMatrix.get_Renamed(column, row))
                        {
                            result[resultOffset++] = (sbyte)readUtah(row, column, numRows, numColumns);
                        }
                        row    -= 2;
                        column += 2;
                    }while ((row >= 0) && (column < numColumns));
                    row    += 1;
                    column += 3;

                    // Sweep downward diagonally to the left
                    do
                    {
                        if ((row >= 0) && (column < numColumns) && !readMappingMatrix.get_Renamed(column, row))
                        {
                            result[resultOffset++] = (sbyte)readUtah(row, column, numRows, numColumns);
                        }
                        row    += 2;
                        column -= 2;
                    }while ((row < numRows) && (column >= 0));
                    row    += 3;
                    column += 1;
                }
            }while ((row < numRows) || (column < numColumns));

            if (resultOffset != version.TotalCodewords)
            {
                throw ReaderException.Instance;
            }
            return(result);
        }
예제 #16
0
		/// <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;
		}