/// <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());
        }
 public DetectionResult(BarcodeMetadata metadata, BoundingBox box)
 {
     Metadata               = metadata;
     Box                    = box;
     ColumnCount            = metadata.ColumnCount;
     DetectionResultColumns = new DetectionResultColumn[ColumnCount + 2];
 }
 /// <summary>
 /// Adjusts the indicator column row numbers.
 /// </summary>
 /// <param name="detectionResultColumn">Detection result column.</param>
 private void adjustIndicatorColumnRowNumbers(DetectionResultColumn detectionResultColumn)
 {
     if (detectionResultColumn != null)
     {
         ((DetectionResultRowIndicatorColumn)detectionResultColumn)
         .adjustCompleteIndicatorColumnRowNumbers(Metadata);
     }
 }
        /// <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));
        }