--- /dev/null
+/*\r
+* Copyright 2009 ZXing authors\r
+*\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*/\r
+using System;\r
+using ReaderException = com.google.zxing.ReaderException;\r
+using ResultPoint = com.google.zxing.ResultPoint;\r
+using BitMatrix = com.google.zxing.common.BitMatrix;\r
+namespace com.google.zxing.common.detector\r
+{\r
+ \r
+ /// <summary> <p>A somewhat generic detector that looks for a barcode-like rectangular region within an image.\r
+ /// It looks within a mostly white region of an image for a region of black and white, but mostly\r
+ /// black. It returns the four corners of the region, as best it can determine.</p>\r
+ /// \r
+ /// </summary>\r
+ /// <author> Sean Owen\r
+ /// </author>\r
+ /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source \r
+ /// </author>\r
+ public sealed class MonochromeRectangleDetector\r
+ {\r
+ \r
+ private const int MAX_MODULES = 32;\r
+ \r
+ //UPGRADE_NOTE: Final was removed from the declaration of 'image '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
+ private BitMatrix image;\r
+ \r
+ public MonochromeRectangleDetector(BitMatrix image)\r
+ {\r
+ this.image = image;\r
+ }\r
+ \r
+ /// <summary> <p>Detects a rectangular region of black and white -- mostly black -- with a region of mostly\r
+ /// white, in an image.</p>\r
+ /// \r
+ /// </summary>\r
+ /// <returns> {@link ResultPoint}[] describing the corners of the rectangular region. The first and\r
+ /// last points are opposed on the diagonal, as are the second and third. The first point will be\r
+ /// the topmost point and the last, the bottommost. The second point will be leftmost and the\r
+ /// third, the rightmost\r
+ /// </returns>\r
+ /// <throws> ReaderException if no Data Matrix Code can be found </throws>\r
+ public ResultPoint[] detect()\r
+ {\r
+ int height = image.Height;\r
+ int width = image.Width;\r
+ int halfHeight = height >> 1;\r
+ int halfWidth = width >> 1;\r
+ int deltaY = System.Math.Max(1, height / (MAX_MODULES << 3));\r
+ int deltaX = System.Math.Max(1, width / (MAX_MODULES << 3));\r
+ \r
+ int top = 0;\r
+ int bottom = height;\r
+ int left = 0;\r
+ int right = width;\r
+ ResultPoint pointA = findCornerFromCenter(halfWidth, 0, left, right, halfHeight, - deltaY, top, bottom, halfWidth >> 1);\r
+ //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'"\r
+ top = (int) pointA.Y - 1;\r
+ ResultPoint pointB = findCornerFromCenter(halfWidth, - deltaX, left, right, halfHeight, 0, top, bottom, halfHeight >> 1);\r
+ //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'"\r
+ left = (int) pointB.X - 1;\r
+ ResultPoint pointC = findCornerFromCenter(halfWidth, deltaX, left, right, halfHeight, 0, top, bottom, halfHeight >> 1);\r
+ //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'"\r
+ right = (int) pointC.X + 1;\r
+ ResultPoint pointD = findCornerFromCenter(halfWidth, 0, left, right, halfHeight, deltaY, top, bottom, halfWidth >> 1);\r
+ //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'"\r
+ bottom = (int) pointD.Y + 1;\r
+ \r
+ // Go try to find point A again with better information -- might have been off at first.\r
+ pointA = findCornerFromCenter(halfWidth, 0, left, right, halfHeight, - deltaY, top, bottom, halfWidth >> 2);\r
+ \r
+ return new ResultPoint[]{pointA, pointB, pointC, pointD};\r
+ }\r
+ \r
+ /// <summary> Attempts to locate a corner of the barcode by scanning up, down, left or right from a center\r
+ /// point which should be within the barcode.\r
+ /// \r
+ /// </summary>\r
+ /// <param name="centerX">center's x component (horizontal)\r
+ /// </param>\r
+ /// <param name="deltaX">same as deltaY but change in x per step instead\r
+ /// </param>\r
+ /// <param name="left">minimum value of x\r
+ /// </param>\r
+ /// <param name="right">maximum value of x\r
+ /// </param>\r
+ /// <param name="centerY">center's y component (vertical)\r
+ /// </param>\r
+ /// <param name="deltaY">change in y per step. If scanning up this is negative; down, positive;\r
+ /// left or right, 0\r
+ /// </param>\r
+ /// <param name="top">minimum value of y to search through (meaningless when di == 0)\r
+ /// </param>\r
+ /// <param name="bottom">maximum value of y\r
+ /// </param>\r
+ /// <param name="maxWhiteRun">maximum run of white pixels that can still be considered to be within\r
+ /// the barcode\r
+ /// </param>\r
+ /// <returns> a {@link com.google.zxing.ResultPoint} encapsulating the corner that was found\r
+ /// </returns>\r
+ /// <throws> com.google.zxing.ReaderException if such a point cannot be found </throws>\r
+ private ResultPoint findCornerFromCenter(int centerX, int deltaX, int left, int right, int centerY, int deltaY, int top, int bottom, int maxWhiteRun)\r
+ {\r
+ int[] lastRange = null;\r
+ for (int y = centerY, x = centerX; y < bottom && y >= top && x < right && x >= left; y += deltaY, x += deltaX)\r
+ {\r
+ int[] range;\r
+ if (deltaX == 0)\r
+ {\r
+ // horizontal slices, up and down\r
+ range = blackWhiteRange(y, maxWhiteRun, left, right, true);\r
+ }\r
+ else\r
+ {\r
+ // vertical slices, left and right\r
+ range = blackWhiteRange(x, maxWhiteRun, top, bottom, false);\r
+ }\r
+ if (range == null)\r
+ {\r
+ if (lastRange == null)\r
+ {\r
+ throw ReaderException.Instance;\r
+ }\r
+ // lastRange was found\r
+ if (deltaX == 0)\r
+ {\r
+ int lastY = y - deltaY;\r
+ if (lastRange[0] < centerX)\r
+ {\r
+ if (lastRange[1] > centerX)\r
+ {\r
+ // straddle, choose one or the other based on direction\r
+ return new ResultPoint(deltaY > 0?lastRange[0]:lastRange[1], lastY);\r
+ }\r
+ return new ResultPoint(lastRange[0], lastY);\r
+ }\r
+ else\r
+ {\r
+ return new ResultPoint(lastRange[1], lastY);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ int lastX = x - deltaX;\r
+ if (lastRange[0] < centerY)\r
+ {\r
+ if (lastRange[1] > centerY)\r
+ {\r
+ return new ResultPoint(lastX, deltaX < 0?lastRange[0]:lastRange[1]);\r
+ }\r
+ return new ResultPoint(lastX, lastRange[0]);\r
+ }\r
+ else\r
+ {\r
+ return new ResultPoint(lastX, lastRange[1]);\r
+ }\r
+ }\r
+ }\r
+ lastRange = range;\r
+ }\r
+ throw ReaderException.Instance;\r
+ }\r
+ \r
+ /// <summary> Computes the start and end of a region of pixels, either horizontally or vertically, that could\r
+ /// be part of a Data Matrix barcode.\r
+ /// \r
+ /// </summary>\r
+ /// <param name="fixedDimension">if scanning horizontally, this is the row (the fixed vertical location)\r
+ /// where we are scanning. If scanning vertically it's the column, the fixed horizontal location\r
+ /// </param>\r
+ /// <param name="maxWhiteRun">largest run of white pixels that can still be considered part of the\r
+ /// barcode region\r
+ /// </param>\r
+ /// <param name="minDim">minimum pixel location, horizontally or vertically, to consider\r
+ /// </param>\r
+ /// <param name="maxDim">maximum pixel location, horizontally or vertically, to consider\r
+ /// </param>\r
+ /// <param name="horizontal">if true, we're scanning left-right, instead of up-down\r
+ /// </param>\r
+ /// <returns> int[] with start and end of found range, or null if no such range is found\r
+ /// (e.g. only white was found)\r
+ /// </returns>\r
+ private int[] blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim, bool horizontal)\r
+ {\r
+ \r
+ int center = (minDim + maxDim) >> 1;\r
+ \r
+ // Scan left/up first\r
+ int start = center;\r
+ while (start >= minDim)\r
+ {\r
+ if (horizontal?image.get_Renamed(start, fixedDimension):image.get_Renamed(fixedDimension, start))\r
+ {\r
+ start--;\r
+ }\r
+ else\r
+ {\r
+ int whiteRunStart = start;\r
+ do \r
+ {\r
+ start--;\r
+ }\r
+ while (start >= minDim && !(horizontal?image.get_Renamed(start, fixedDimension):image.get_Renamed(fixedDimension, start)));\r
+ int whiteRunSize = whiteRunStart - start;\r
+ if (start < minDim || whiteRunSize > maxWhiteRun)\r
+ {\r
+ start = whiteRunStart;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ start++;\r
+ \r
+ // Then try right/down\r
+ int end = center;\r
+ while (end < maxDim)\r
+ {\r
+ if (horizontal?image.get_Renamed(end, fixedDimension):image.get_Renamed(fixedDimension, end))\r
+ {\r
+ end++;\r
+ }\r
+ else\r
+ {\r
+ int whiteRunStart = end;\r
+ do \r
+ {\r
+ end++;\r
+ }\r
+ while (end < maxDim && !(horizontal?image.get_Renamed(end, fixedDimension):image.get_Renamed(fixedDimension, end)));\r
+ int whiteRunSize = end - whiteRunStart;\r
+ if (end >= maxDim || whiteRunSize > maxWhiteRun)\r
+ {\r
+ end = whiteRunStart;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ end--;\r
+ \r
+ return end > start?new int[]{start, end}:null;\r
+ }\r
+ }\r
+}
\ No newline at end of file