/// <summary> /// Adjusts the row numbers from both Row Indicators /// </summary> /// <returns> zero </returns> private void adjustRowNumbersFromBothRI() { if (DetectionResultColumns[0] == null || DetectionResultColumns[ColumnCount + 1] == null) { return; } Codeword[] LRIcodewords = DetectionResultColumns[0].Codewords; Codeword[] RRIcodewords = DetectionResultColumns[ColumnCount + 1].Codewords; for (int codewordsRow = 0; codewordsRow < LRIcodewords.Length; codewordsRow++) { if (LRIcodewords[codewordsRow] != null && RRIcodewords[codewordsRow] != null && LRIcodewords[codewordsRow].RowNumber == RRIcodewords[codewordsRow].RowNumber) { for (int barcodeColumn = 1; barcodeColumn <= ColumnCount; barcodeColumn++) { Codeword codeword = DetectionResultColumns[barcodeColumn].Codewords[codewordsRow]; if (codeword == null) { continue; } codeword.RowNumber = LRIcodewords[codewordsRow].RowNumber; if (!codeword.HasValidRowNumber) { // LOG.info("Removing codeword with invalid row number, cw[" + codewordsRow + "][" + barcodeColumn + "]"); DetectionResultColumns[barcodeColumn].Codewords[codewordsRow] = null; } } } } }
/// <summary> /// Returns a <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.DetectionResult"/>. /// </summary> /// <returns>A <see cref="System.String"/> that represents the current <see cref="ZXing.PDF417.Internal.DetectionResult"/>.</returns> public override string ToString() { StringBuilder formatter = new StringBuilder(); DetectionResultColumn rowIndicatorColumn = DetectionResultColumns[0]; if (rowIndicatorColumn == null) { rowIndicatorColumn = DetectionResultColumns[ColumnCount + 1]; } for (int codewordsRow = 0; codewordsRow < rowIndicatorColumn.Codewords.Length; codewordsRow++) { formatter.AppendFormat(CultureInfo.InvariantCulture, "CW {0,3}:", codewordsRow); for (int barcodeColumn = 0; barcodeColumn < ColumnCount + 2; barcodeColumn++) { if (DetectionResultColumns[barcodeColumn] == null) { formatter.Append(" | "); continue; } Codeword codeword = DetectionResultColumns[barcodeColumn].Codewords[codewordsRow]; if (codeword == null) { formatter.Append(" | "); continue; } formatter.AppendFormat(CultureInfo.InvariantCulture, " {0,3}|{1,3}", codeword.RowNumber, codeword.Value); } formatter.Append("\n"); } return(formatter.ToString()); }
/// <summary> /// Adjusts the row numbers from Left Row Indicator. /// </summary> /// <returns> Unadjusted row Count.</returns> private int adjustRowNumbersFromLRI() { if (DetectionResultColumns[0] == null) { return(0); } int unadjustedCount = 0; Codeword[] codewords = DetectionResultColumns[0].Codewords; for (int codewordsRow = 0; codewordsRow < codewords.Length; codewordsRow++) { if (codewords[codewordsRow] == null) { continue; } int rowIndicatorRowNumber = codewords[codewordsRow].RowNumber; int invalidRowCounts = 0; for (int barcodeColumn = 1; barcodeColumn < ColumnCount + 1 && invalidRowCounts < ADJUST_ROW_NUMBER_SKIP; barcodeColumn++) { Codeword codeword = DetectionResultColumns[barcodeColumn].Codewords[codewordsRow]; if (codeword != null) { invalidRowCounts = adjustRowNumberIfValid(rowIndicatorRowNumber, invalidRowCounts, codeword); if (!codeword.HasValidRowNumber) { unadjustedCount++; } } } } return(unadjustedCount); }
/// <summary> /// Gets the row indicator column. /// </summary> /// <returns>The row indicator column.</returns> /// <param name="image">Image.</param> /// <param name="boundingBox">Bounding box.</param> /// <param name="startPoint">Start point.</param> /// <param name="leftToRight">If set to <c>true</c> left to right.</param> /// <param name="minCodewordWidth">Minimum codeword width.</param> /// <param name="maxCodewordWidth">Max codeword width.</param> private static DetectionResultRowIndicatorColumn getRowIndicatorColumn(BitMatrix image, BoundingBox boundingBox, ResultPoint startPoint, bool leftToRight, int minCodewordWidth, int maxCodewordWidth) { DetectionResultRowIndicatorColumn rowIndicatorColumn = new DetectionResultRowIndicatorColumn(boundingBox, leftToRight); for (int i = 0; i < 2; i++) { int increment = i == 0 ? 1 : -1; int startColumn = (int)startPoint.X; for (int imageRow = (int)startPoint.Y; imageRow <= boundingBox.MaxY && imageRow >= boundingBox.MinY; imageRow += increment) { Codeword codeword = detectCodeword(image, 0, image.Width, leftToRight, startColumn, imageRow, minCodewordWidth, maxCodewordWidth); if (codeword != null) { rowIndicatorColumn.setCodeword(imageRow, codeword); if (leftToRight) { startColumn = codeword.StartX; } else { startColumn = codeword.EndX; } } } } return(rowIndicatorColumn); }
/// <summary> /// Gets the codeword closest to the specified row in the image /// </summary> /// <param name="imageRow">Image row.</param> public Codeword getCodewordNearby(int imageRow) { Codeword codeword = getCodeword(imageRow); if (codeword != null) { return(codeword); } for (int i = 1; i < MAX_NEARBY_DISTANCE; i++) { int nearImageRow = imageRowToCodewordIndex(imageRow) - i; if (nearImageRow >= 0) { codeword = Codewords[nearImageRow]; if (codeword != null) { return(codeword); } } nearImageRow = imageRowToCodewordIndex(imageRow) + i; if (nearImageRow < Codewords.Length) { codeword = Codewords[nearImageRow]; if (codeword != null) { return(codeword); } } } return(null); }
/// <summary> /// Adjusts the row number. /// </summary> /// <returns><c>true</c>, if row number was adjusted, <c>false</c> otherwise.</returns> /// <param name="codeword">Codeword.</param> /// <param name="otherCodeword">Other codeword.</param> private static bool adjustRowNumber(Codeword codeword, Codeword otherCodeword) { if (otherCodeword == null) { return(false); } if (otherCodeword.HasValidRowNumber && otherCodeword.Bucket == codeword.Bucket) { codeword.RowNumber = otherCodeword.RowNumber; return(true); } return(false); }
/// <summary> /// Adjusts the row numbers. /// </summary> /// <param name="barcodeColumn">Barcode column.</param> /// <param name="codewordsRow">Codewords row.</param> /// <param name="codewords">Codewords.</param> private void adjustRowNumbers(int barcodeColumn, int codewordsRow, Codeword[] codewords) { Codeword codeword = codewords[codewordsRow]; Codeword[] previousColumnCodewords = DetectionResultColumns[barcodeColumn - 1].Codewords; Codeword[] nextColumnCodewords = previousColumnCodewords; if (DetectionResultColumns[barcodeColumn + 1] != null) { nextColumnCodewords = DetectionResultColumns[barcodeColumn + 1].Codewords; } Codeword[] otherCodewords = new Codeword[14]; otherCodewords[2] = previousColumnCodewords[codewordsRow]; otherCodewords[3] = nextColumnCodewords[codewordsRow]; if (codewordsRow > 0) { otherCodewords[0] = codewords[codewordsRow - 1]; otherCodewords[4] = previousColumnCodewords[codewordsRow - 1]; otherCodewords[5] = nextColumnCodewords[codewordsRow - 1]; } if (codewordsRow > 1) { otherCodewords[8] = codewords[codewordsRow - 2]; otherCodewords[10] = previousColumnCodewords[codewordsRow - 2]; otherCodewords[11] = nextColumnCodewords[codewordsRow - 2]; } if (codewordsRow < codewords.Length - 1) { otherCodewords[1] = codewords[codewordsRow + 1]; otherCodewords[6] = previousColumnCodewords[codewordsRow + 1]; otherCodewords[7] = nextColumnCodewords[codewordsRow + 1]; } if (codewordsRow < codewords.Length - 2) { otherCodewords[9] = codewords[codewordsRow + 2]; otherCodewords[12] = previousColumnCodewords[codewordsRow + 2]; otherCodewords[13] = nextColumnCodewords[codewordsRow + 2]; } foreach (Codeword otherCodeword in otherCodewords) { if (adjustRowNumber(codeword, otherCodeword)) { return; } } }
/// <summary> /// Gets the start column. /// </summary> /// <returns>The start column.</returns> /// <param name="detectionResult">Detection result.</param> /// <param name="barcodeColumn">Barcode column.</param> /// <param name="imageRow">Image row.</param> /// <param name="leftToRight">If set to <c>true</c> left to right.</param> private static int getStartColumn(DetectionResult detectionResult, int barcodeColumn, int imageRow, bool leftToRight) { int offset = leftToRight ? 1 : -1; Codeword codeword = null; if (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) { codeword = detectionResult.DetectionResultColumns[barcodeColumn - offset].getCodeword(imageRow); } if (codeword != null) { return(leftToRight ? codeword.EndX : codeword.StartX); } codeword = detectionResult.DetectionResultColumns[barcodeColumn].getCodewordNearby(imageRow); if (codeword != null) { return(leftToRight ? codeword.StartX : codeword.EndX); } if (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) { codeword = detectionResult.DetectionResultColumns[barcodeColumn - offset].getCodewordNearby(imageRow); } if (codeword != null) { return(leftToRight ? codeword.EndX : codeword.StartX); } int skippedColumns = 0; while (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) { barcodeColumn -= offset; foreach (Codeword previousRowCodeword in detectionResult.DetectionResultColumns[barcodeColumn].Codewords) { if (previousRowCodeword != null) { return((leftToRight ? previousRowCodeword.EndX : previousRowCodeword.StartX) + offset * skippedColumns * (previousRowCodeword.EndX - previousRowCodeword.StartX)); } } skippedColumns++; } return(leftToRight ? detectionResult.Box.MinX : detectionResult.Box.MaxX); }
/// <summary> /// Adjusts the row number if valid. /// </summary> /// <returns>The invalid rows</returns> /// <param name="rowIndicatorRowNumber">Row indicator row number.</param> /// <param name="invalidRowCounts">Invalid row counts.</param> /// <param name="codeword">Codeword.</param> private static int adjustRowNumberIfValid(int rowIndicatorRowNumber, int invalidRowCounts, Codeword codeword) { if (codeword == null) { return(invalidRowCounts); } if (!codeword.HasValidRowNumber) { if (codeword.IsValidRowNumber(rowIndicatorRowNumber)) { codeword.RowNumber = rowIndicatorRowNumber; invalidRowCounts = 0; } else { ++invalidRowCounts; } } return(invalidRowCounts); }
/// <summary> /// Decode the specified image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight, minCodewordWidth /// and maxCodewordWidth. /// TODO: don't pass in minCodewordWidth and maxCodewordWidth, pass in barcode columns for start and stop pattern /// columns. That way width can be deducted from the pattern column. /// This approach also allows to detect more details about the barcode, e.g. if a bar type (white or black) is wider /// than it should be. This can happen if the scanner used a bad blackpoint. /// </summary> /// <param name="image">Image.</param> /// <param name="imageTopLeft">Image top left.</param> /// <param name="imageBottomLeft">Image bottom left.</param> /// <param name="imageTopRight">Image top right.</param> /// <param name="imageBottomRight">Image bottom right.</param> /// <param name="minCodewordWidth">Minimum codeword width.</param> /// <param name="maxCodewordWidth">Max codeword width.</param> public static DecoderResult decode(BitMatrix image, ResultPoint imageTopLeft, ResultPoint imageBottomLeft, ResultPoint imageTopRight, ResultPoint imageBottomRight, int minCodewordWidth, int maxCodewordWidth) { BoundingBox boundingBox = BoundingBox.Create(image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight); if (boundingBox == null) { return(null); } DetectionResultRowIndicatorColumn leftRowIndicatorColumn = null; DetectionResultRowIndicatorColumn rightRowIndicatorColumn = null; DetectionResult detectionResult = null; for (int i = 0; i < 2; i++) { if (imageTopLeft != null) { leftRowIndicatorColumn = getRowIndicatorColumn(image, boundingBox, imageTopLeft, true, minCodewordWidth, maxCodewordWidth); } if (imageTopRight != null) { rightRowIndicatorColumn = getRowIndicatorColumn(image, boundingBox, imageTopRight, false, minCodewordWidth, maxCodewordWidth); } detectionResult = merge(leftRowIndicatorColumn, rightRowIndicatorColumn); if (detectionResult == null) { // TODO Based on Owen's Comments in <see cref="ZXing.ReaderException"/>, this method has been modified to continue silently // if a barcode was not decoded where it was detected instead of throwing a new exception object. return(null); } if (i == 0 && detectionResult.Box != null && (detectionResult.Box.MinY < boundingBox.MinY || detectionResult.Box.MaxY > boundingBox.MaxY)) { boundingBox = detectionResult.Box; } else { detectionResult.Box = boundingBox; break; } } int maxBarcodeColumn = detectionResult.ColumnCount + 1; detectionResult.DetectionResultColumns[0] = leftRowIndicatorColumn; detectionResult.DetectionResultColumns[maxBarcodeColumn] = rightRowIndicatorColumn; bool leftToRight = leftRowIndicatorColumn != null; for (int barcodeColumnCount = 1; barcodeColumnCount <= maxBarcodeColumn; barcodeColumnCount++) { int barcodeColumn = leftToRight ? barcodeColumnCount : maxBarcodeColumn - barcodeColumnCount; if (detectionResult.DetectionResultColumns[barcodeColumn] != null) { // This will be the case for the opposite row indicator column, which doesn't need to be decoded again. continue; } DetectionResultColumn detectionResultColumn; if (barcodeColumn == 0 || barcodeColumn == maxBarcodeColumn) { detectionResultColumn = new DetectionResultRowIndicatorColumn(boundingBox, barcodeColumn == 0); } else { detectionResultColumn = new DetectionResultColumn(boundingBox); } detectionResult.DetectionResultColumns[barcodeColumn] = detectionResultColumn; int startColumn = -1; int previousStartColumn = startColumn; // TODO start at a row for which we know the start position, then detect upwards and downwards from there. for (int imageRow = boundingBox.MinY; imageRow <= boundingBox.MaxY; imageRow++) { startColumn = getStartColumn(detectionResult, barcodeColumn, imageRow, leftToRight); if (startColumn < 0 || startColumn > boundingBox.MaxX) { if (previousStartColumn == -1) { continue; } startColumn = previousStartColumn; } Codeword codeword = detectCodeword(image, boundingBox.MinX, boundingBox.MaxX, leftToRight, startColumn, imageRow, minCodewordWidth, maxCodewordWidth); if (codeword != null) { detectionResultColumn.setCodeword(imageRow, codeword); previousStartColumn = startColumn; minCodewordWidth = Math.Min(minCodewordWidth, codeword.Width); maxCodewordWidth = Math.Max(maxCodewordWidth, codeword.Width); } } } return(createDecoderResult(detectionResult)); }
/// <summary> /// Sets the codeword for an image row /// </summary> /// <param name="imageRow">Image row.</param> /// <param name="codeword">Codeword.</param> public void setCodeword(int imageRow, Codeword codeword) { Codewords[IndexForRow(imageRow)] = codeword; }