Represents a Column in the Detection Result
Inheritance: ZXing.PDF417.Internal.DetectionResultColumn
        /// <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 barcode metadata.
        /// </summary>
        /// <returns>The barcode metadata.</returns>
        /// <param name="leftRowIndicatorColumn">Left row indicator column.</param>
        /// <param name="rightRowIndicatorColumn">Right row indicator column.</param>
        private static BarcodeMetadata getBarcodeMetadata(DetectionResultRowIndicatorColumn leftRowIndicatorColumn,
                                                          DetectionResultRowIndicatorColumn rightRowIndicatorColumn)
        {
            BarcodeMetadata leftBarcodeMetadata;

            if (leftRowIndicatorColumn == null ||
                (leftBarcodeMetadata = leftRowIndicatorColumn.getBarcodeMetadata()) == null)
            {
                return(rightRowIndicatorColumn == null ? null : rightRowIndicatorColumn.getBarcodeMetadata());
            }
            BarcodeMetadata rightBarcodeMetadata;

            if (rightRowIndicatorColumn == null ||
                (rightBarcodeMetadata = rightRowIndicatorColumn.getBarcodeMetadata()) == null)
            {
                return(leftBarcodeMetadata);
            }

            if (leftBarcodeMetadata.ColumnCount != rightBarcodeMetadata.ColumnCount &&
                leftBarcodeMetadata.ErrorCorrectionLevel != rightBarcodeMetadata.ErrorCorrectionLevel &&
                leftBarcodeMetadata.RowCount != rightBarcodeMetadata.RowCount)
            {
                return(null);
            }
            return(leftBarcodeMetadata);
        }
        /// <summary>
        /// Gets the bounding box.
        /// </summary>
        /// <returns>The bounding box.</returns>
        /// <param name="leftRowIndicatorColumn">Left row indicator column.</param>
        /// <param name="rightRowIndicatorColumn">Right row indicator column.</param>
        private static BoundingBox GetBoundingBox(DetectionResultRowIndicatorColumn leftRowIndicatorColumn,
                                                  DetectionResultRowIndicatorColumn rightRowIndicatorColumn)
        {
            BoundingBox box1 = AdjustBoundingBox(leftRowIndicatorColumn);
            BoundingBox box2 = AdjustBoundingBox(rightRowIndicatorColumn);

            return(BoundingBox.Merge(box1, box2));
        }
        /// <summary>
        /// Merge the specified leftRowIndicatorColumn and rightRowIndicatorColumn.
        /// </summary>
        /// <param name="leftRowIndicatorColumn">Left row indicator column.</param>
        /// <param name="rightRowIndicatorColumn">Right row indicator column.</param>
        private static DetectionResult Merge(DetectionResultRowIndicatorColumn leftRowIndicatorColumn,
                                             DetectionResultRowIndicatorColumn rightRowIndicatorColumn)
        {
            if (leftRowIndicatorColumn == null && rightRowIndicatorColumn == null)
            {
                return(null);
            }
            BarcodeMetadata barcodeMetadata = GetBarcodeMetadata(leftRowIndicatorColumn, rightRowIndicatorColumn);

            if (barcodeMetadata == null)
            {
                return(null);
            }
            BoundingBox boundingBox = GetBoundingBox(leftRowIndicatorColumn, rightRowIndicatorColumn);

            return(new DetectionResult(barcodeMetadata, boundingBox));
        }
        /// <summary>
        /// Adjusts the bounding box.
        /// </summary>
        /// <returns>The bounding box.</returns>
        /// <param name="rowIndicatorColumn">Row indicator column.</param>
        private static BoundingBox adjustBoundingBox(DetectionResultRowIndicatorColumn rowIndicatorColumn)
        {
            if (rowIndicatorColumn == null)
            {
                return(null);
            }
            int[] rowHeights = rowIndicatorColumn.getRowHeights();
            if (rowHeights == null)
            {
                return(null);
            }
            int maxRowHeight     = getMax(rowHeights);
            int missingStartRows = 0;

            foreach (int rowHeight in rowHeights)
            {
                missingStartRows += maxRowHeight - rowHeight;
                if (rowHeight > 0)
                {
                    break;
                }
            }
            Codeword[] codewords = rowIndicatorColumn.Codewords;
            for (int row = 0; missingStartRows > 0 && codewords[row] == null; row++)
            {
                missingStartRows--;
            }
            int missingEndRows = 0;

            for (int row = rowHeights.Length - 1; row >= 0; row--)
            {
                missingEndRows += maxRowHeight - rowHeights[row];
                if (rowHeights[row] > 0)
                {
                    break;
                }
            }
            for (int row = codewords.Length - 1; missingEndRows > 0 && codewords[row] == null; row--)
            {
                missingEndRows--;
            }
            return(rowIndicatorColumn.Box.addMissingRows(missingStartRows, missingEndRows, rowIndicatorColumn.IsLeft));
        }
      /// <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>
 /// 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 barcode metadata.
      /// </summary>
      /// <returns>The barcode metadata.</returns>
      /// <param name="leftRowIndicatorColumn">Left row indicator column.</param>
      /// <param name="rightRowIndicatorColumn">Right row indicator column.</param>
      private static BarcodeMetadata getBarcodeMetadata(DetectionResultRowIndicatorColumn leftRowIndicatorColumn,
                                                        DetectionResultRowIndicatorColumn rightRowIndicatorColumn)
      {

         BarcodeMetadata leftBarcodeMetadata;
         if (leftRowIndicatorColumn == null ||
             (leftBarcodeMetadata = leftRowIndicatorColumn.getBarcodeMetadata()) == null)
         {
            return rightRowIndicatorColumn == null ? null : rightRowIndicatorColumn.getBarcodeMetadata();
         }
         BarcodeMetadata rightBarcodeMetadata;
         if (rightRowIndicatorColumn == null ||
             (rightBarcodeMetadata = rightRowIndicatorColumn.getBarcodeMetadata()) == null)
         {
            return leftBarcodeMetadata;
         }

         if (leftBarcodeMetadata.ColumnCount != rightBarcodeMetadata.ColumnCount &&
             leftBarcodeMetadata.ErrorCorrectionLevel != rightBarcodeMetadata.ErrorCorrectionLevel &&
             leftBarcodeMetadata.RowCount != rightBarcodeMetadata.RowCount)
         {
            return null;
         }
         return leftBarcodeMetadata;
      }
 /// <summary>
 /// Adjusts the bounding box.
 /// </summary>
 /// <returns>The bounding box.</returns>
 /// <param name="rowIndicatorColumn">Row indicator column.</param>
 private static BoundingBox adjustBoundingBox(DetectionResultRowIndicatorColumn rowIndicatorColumn)
 {
    if (rowIndicatorColumn == null)
    {
       return null;
    }
    int[] rowHeights = rowIndicatorColumn.getRowHeights();
    if (rowHeights == null)
    {
       return null;
    }
    int maxRowHeight = getMax(rowHeights);
    int missingStartRows = 0;
    foreach (int rowHeight in rowHeights)
    {
       missingStartRows += maxRowHeight - rowHeight;
       if (rowHeight > 0)
       {
          break;
       }
    }
    Codeword[] codewords = rowIndicatorColumn.Codewords;
    for (int row = 0; missingStartRows > 0 && codewords[row] == null; row++)
    {
       missingStartRows--;
    }
    int missingEndRows = 0;
    for (int row = rowHeights.Length - 1; row >= 0; row--)
    {
       missingEndRows += maxRowHeight - rowHeights[row];
       if (rowHeights[row] > 0)
       {
          break;
       }
    }
    for (int row = codewords.Length - 1; missingEndRows > 0 && codewords[row] == null; row--)
    {
       missingEndRows--;
    }
    return rowIndicatorColumn.Box.addMissingRows(missingStartRows, missingEndRows, rowIndicatorColumn.IsLeft);
 }
      /// <summary>
      /// Merge the specified leftRowIndicatorColumn and rightRowIndicatorColumn.
      /// </summary>
      /// <param name="leftRowIndicatorColumn">Left row indicator column.</param>
      /// <param name="rightRowIndicatorColumn">Right row indicator column.</param>
      private static DetectionResult merge(DetectionResultRowIndicatorColumn leftRowIndicatorColumn,
                                           DetectionResultRowIndicatorColumn rightRowIndicatorColumn)
      {
         if (leftRowIndicatorColumn == null && rightRowIndicatorColumn == null)
         {
            return null;
         }
         BarcodeMetadata barcodeMetadata = getBarcodeMetadata(leftRowIndicatorColumn, rightRowIndicatorColumn);
         if (barcodeMetadata == null)
         {
            return null;
         }
         BoundingBox boundingBox = BoundingBox.merge(adjustBoundingBox(leftRowIndicatorColumn),
                                                     adjustBoundingBox(rightRowIndicatorColumn));

         return new DetectionResult(barcodeMetadata, boundingBox);
      }
示例#11
0
        /// <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>
 /// Gets the bounding box.
 /// </summary>
 /// <returns>The bounding box.</returns>
 /// <param name="leftRowIndicatorColumn">Left row indicator column.</param>
 /// <param name="rightRowIndicatorColumn">Right row indicator column.</param>
 private static BoundingBox GetBoundingBox(DetectionResultRowIndicatorColumn leftRowIndicatorColumn,
                                           DetectionResultRowIndicatorColumn rightRowIndicatorColumn)
 {
     BoundingBox box1 = AdjustBoundingBox(leftRowIndicatorColumn);
     BoundingBox box2 = AdjustBoundingBox(rightRowIndicatorColumn);
     
     return BoundingBox.Merge(box1, box2);
 }