--- /dev/null
+/*\r
+* Copyright 2008 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 BinaryBitmap = com.google.zxing.BinaryBitmap;\r
+using DecodeHintType = com.google.zxing.DecodeHintType;\r
+using Reader = com.google.zxing.Reader;\r
+using ReaderException = com.google.zxing.ReaderException;\r
+using Result = com.google.zxing.Result;\r
+using ResultMetadataType = com.google.zxing.ResultMetadataType;\r
+using ResultPoint = com.google.zxing.ResultPoint;\r
+using BitArray = com.google.zxing.common.BitArray;\r
+namespace com.google.zxing.oned\r
+{\r
+ \r
+ /// <summary> Encapsulates functionality and implementation that is common to all families\r
+ /// of one-dimensional barcodes.\r
+ /// \r
+ /// </summary>\r
+ /// <author> dswitkin@google.com (Daniel Switkin)\r
+ /// </author>\r
+ /// <author> Sean Owen\r
+ /// </author>\r
+ /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source \r
+ /// </author>\r
+ public abstract class OneDReader : Reader\r
+ {\r
+ \r
+ private const int INTEGER_MATH_SHIFT = 8;\r
+ //UPGRADE_NOTE: Final was removed from the declaration of 'PATTERN_MATCH_RESULT_SCALE_FACTOR '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
+ internal static readonly int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;\r
+ \r
+ public virtual Result decode(BinaryBitmap image)\r
+ {\r
+ return decode(image, null);\r
+ }\r
+ \r
+ // Note that we don't try rotation without the try harder flag, even if rotation was supported.\r
+ public virtual Result decode(BinaryBitmap image, System.Collections.Hashtable hints)\r
+ {\r
+ try\r
+ {\r
+ return doDecode(image, hints);\r
+ }\r
+ catch (ReaderException re)\r
+ {\r
+ bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER);\r
+ if (tryHarder && image.RotateSupported)\r
+ {\r
+ BinaryBitmap rotatedImage = image.rotateCounterClockwise();\r
+ Result result = doDecode(rotatedImage, hints);\r
+ // Record that we found it rotated 90 degrees CCW / 270 degrees CW\r
+ System.Collections.Hashtable metadata = result.ResultMetadata;\r
+ int orientation = 270;\r
+ if (metadata != null && metadata.ContainsKey(ResultMetadataType.ORIENTATION))\r
+ {\r
+ // But if we found it reversed in doDecode(), add in that result here:\r
+ orientation = (orientation + ((System.Int32) metadata[ResultMetadataType.ORIENTATION])) % 360;\r
+ }\r
+ result.putMetadata(ResultMetadataType.ORIENTATION, (System.Object) orientation);\r
+ // Update result points\r
+ ResultPoint[] points = result.ResultPoints;\r
+ int height = rotatedImage.Height;\r
+ for (int i = 0; i < points.Length; i++)\r
+ {\r
+ points[i] = new ResultPoint(height - points[i].Y - 1, points[i].X);\r
+ }\r
+ return result;\r
+ }\r
+ else\r
+ {\r
+ throw re;\r
+ }\r
+ }\r
+ }\r
+ \r
+ /// <summary> We're going to examine rows from the middle outward, searching alternately above and below the\r
+ /// middle, and farther out each time. rowStep is the number of rows between each successive\r
+ /// attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then\r
+ /// middle + rowStep, then middle - (2 * rowStep), etc.\r
+ /// rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily\r
+ /// decided that moving up and down by about 1/16 of the image is pretty good; we try more of the\r
+ /// image if "trying harder".\r
+ /// \r
+ /// </summary>\r
+ /// <param name="image">The image to decode\r
+ /// </param>\r
+ /// <param name="hints">Any hints that were requested\r
+ /// </param>\r
+ /// <returns> The contents of the decoded barcode\r
+ /// </returns>\r
+ /// <throws> ReaderException Any spontaneous errors which occur </throws>\r
+ private Result doDecode(BinaryBitmap image, System.Collections.Hashtable hints)\r
+ {\r
+ int width = image.Width;\r
+ int height = image.Height;\r
+ BitArray row = new BitArray(width);\r
+ \r
+ int middle = height >> 1;\r
+ bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER);\r
+ int rowStep = System.Math.Max(1, height >> (tryHarder?7:4));\r
+ int maxLines;\r
+ if (tryHarder)\r
+ {\r
+ maxLines = height; // Look at the whole image, not just the center\r
+ }\r
+ else\r
+ {\r
+ maxLines = 9; // Nine rows spaced 1/16 apart is roughly the middle half of the image\r
+ }\r
+ \r
+ for (int x = 0; x < maxLines; x++)\r
+ {\r
+ \r
+ // Scanning from the middle out. Determine which row we're looking at next:\r
+ int rowStepsAboveOrBelow = (x + 1) >> 1;\r
+ bool isAbove = (x & 0x01) == 0; // i.e. is x even?\r
+ int rowNumber = middle + rowStep * (isAbove?rowStepsAboveOrBelow:- rowStepsAboveOrBelow);\r
+ if (rowNumber < 0 || rowNumber >= height)\r
+ {\r
+ // Oops, if we run off the top or bottom, stop\r
+ break;\r
+ }\r
+ \r
+ // Estimate black point for this row and load it:\r
+ try\r
+ {\r
+ row = image.getBlackRow(rowNumber, row);\r
+ }\r
+ catch (ReaderException re)\r
+ {\r
+ continue;\r
+ }\r
+ \r
+ // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to\r
+ // handle decoding upside down barcodes.\r
+ for (int attempt = 0; attempt < 2; attempt++)\r
+ {\r
+ if (attempt == 1)\r
+ {\r
+ // trying again?\r
+ row.reverse(); // reverse the row and continue\r
+ // This means we will only ever draw result points *once* in the life of this method\r
+ // since we want to avoid drawing the wrong points after flipping the row, and,\r
+ // don't want to clutter with noise from every single row scan -- just the scans\r
+ // that start on the center line.\r
+ if (hints != null && hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK))\r
+ {\r
+ System.Collections.Hashtable newHints = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable()); // Can't use clone() in J2ME\r
+ System.Collections.IEnumerator hintEnum = hints.Keys.GetEnumerator();\r
+ //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'"\r
+ while (hintEnum.MoveNext())\r
+ {\r
+ //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'"\r
+ System.Object key = hintEnum.Current;\r
+ if (!key.Equals(DecodeHintType.NEED_RESULT_POINT_CALLBACK))\r
+ {\r
+ newHints[key] = hints[key];\r
+ }\r
+ }\r
+ hints = newHints;\r
+ }\r
+ }\r
+ try\r
+ {\r
+ // Look for a barcode\r
+ Result result = decodeRow(rowNumber, row, hints);\r
+ // We found our barcode\r
+ if (attempt == 1)\r
+ {\r
+ // But it was upside down, so note that\r
+ result.putMetadata(ResultMetadataType.ORIENTATION, (System.Object) 180);\r
+ // And remember to flip the result points horizontally.\r
+ ResultPoint[] points = result.ResultPoints;\r
+ points[0] = new ResultPoint(width - points[0].X - 1, points[0].Y);\r
+ points[1] = new ResultPoint(width - points[1].X - 1, points[1].Y);\r
+ }\r
+ return result;\r
+ }\r
+ catch (ReaderException re)\r
+ {\r
+ // continue -- just couldn't decode this row\r
+ }\r
+ }\r
+ }\r
+ \r
+ throw ReaderException.Instance;\r
+ }\r
+ \r
+ /// <summary> Records the size of successive runs of white and black pixels in a row, starting at a given point.\r
+ /// The values are recorded in the given array, and the number of runs recorded is equal to the size\r
+ /// of the array. If the row starts on a white pixel at the given start point, then the first count\r
+ /// recorded is the run of white pixels starting from that point; likewise it is the count of a run\r
+ /// of black pixels if the row begin on a black pixels at that point.\r
+ /// \r
+ /// </summary>\r
+ /// <param name="row">row to count from\r
+ /// </param>\r
+ /// <param name="start">offset into row to start at\r
+ /// </param>\r
+ /// <param name="counters">array into which to record counts\r
+ /// </param>\r
+ /// <throws> ReaderException if counters cannot be filled entirely from row before running out </throws>\r
+ /// <summary> of pixels\r
+ /// </summary>\r
+ internal static void recordPattern(BitArray row, int start, int[] counters)\r
+ {\r
+ int numCounters = counters.Length;\r
+ for (int i = 0; i < numCounters; i++)\r
+ {\r
+ counters[i] = 0;\r
+ }\r
+ int end = row.Size;\r
+ if (start >= end)\r
+ {\r
+ throw ReaderException.Instance;\r
+ }\r
+ bool isWhite = !row.get_Renamed(start);\r
+ int counterPosition = 0;\r
+ int i2 = start;\r
+ while (i2 < end)\r
+ {\r
+ bool pixel = row.get_Renamed(i2);\r
+ if (pixel ^ isWhite)\r
+ {\r
+ // that is, exactly one is true\r
+ counters[counterPosition]++;\r
+ }\r
+ else\r
+ {\r
+ counterPosition++;\r
+ if (counterPosition == numCounters)\r
+ {\r
+ break;\r
+ }\r
+ else\r
+ {\r
+ counters[counterPosition] = 1;\r
+ isWhite ^= true; // isWhite = !isWhite;\r
+ }\r
+ }\r
+ i2++;\r
+ }\r
+ // If we read fully the last section of pixels and filled up our counters -- or filled\r
+ // the last counter but ran off the side of the image, OK. Otherwise, a problem.\r
+ if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i2 == end)))\r
+ {\r
+ throw ReaderException.Instance;\r
+ }\r
+ }\r
+ \r
+ /// <summary> Determines how closely a set of observed counts of runs of black/white values matches a given\r
+ /// target pattern. This is reported as the ratio of the total variance from the expected pattern\r
+ /// proportions across all pattern elements, to the length of the pattern.\r
+ /// \r
+ /// </summary>\r
+ /// <param name="counters">observed counters\r
+ /// </param>\r
+ /// <param name="pattern">expected pattern\r
+ /// </param>\r
+ /// <param name="maxIndividualVariance">The most any counter can differ before we give up\r
+ /// </param>\r
+ /// <returns> ratio of total variance between counters and pattern compared to total pattern size,\r
+ /// where the ratio has been multiplied by 256. So, 0 means no variance (perfect match); 256 means\r
+ /// the total variance between counters and patterns equals the pattern length, higher values mean\r
+ /// even more variance\r
+ /// </returns>\r
+ internal static int patternMatchVariance(int[] counters, int[] pattern, int maxIndividualVariance)\r
+ {\r
+ int numCounters = counters.Length;\r
+ int total = 0;\r
+ int patternLength = 0;\r
+ for (int i = 0; i < numCounters; i++)\r
+ {\r
+ total += counters[i];\r
+ patternLength += pattern[i];\r
+ }\r
+ if (total < patternLength)\r
+ {\r
+ // If we don't even have one pixel per unit of bar width, assume this is too small\r
+ // to reliably match, so fail:\r
+ return System.Int32.MaxValue;\r
+ }\r
+ // We're going to fake floating-point math in integers. We just need to use more bits.\r
+ // Scale up patternLength so that intermediate values below like scaledCounter will have\r
+ // more "significant digits"\r
+ int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;\r
+ maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;\r
+ \r
+ int totalVariance = 0;\r
+ for (int x = 0; x < numCounters; x++)\r
+ {\r
+ int counter = counters[x] << INTEGER_MATH_SHIFT;\r
+ int scaledPattern = pattern[x] * unitBarWidth;\r
+ int variance = counter > scaledPattern?counter - scaledPattern:scaledPattern - counter;\r
+ if (variance > maxIndividualVariance)\r
+ {\r
+ return System.Int32.MaxValue;\r
+ }\r
+ totalVariance += variance;\r
+ }\r
+ return totalVariance / total;\r
+ }\r
+ \r
+ /// <summary> <p>Attempts to decode a one-dimensional barcode format given a single row of\r
+ /// an image.</p>\r
+ /// \r
+ /// </summary>\r
+ /// <param name="rowNumber">row number from top of the row\r
+ /// </param>\r
+ /// <param name="row">the black/white pixel data of the row\r
+ /// </param>\r
+ /// <param name="hints">decode hints\r
+ /// </param>\r
+ /// <returns> {@link Result} containing encoded string and start/end of barcode\r
+ /// </returns>\r
+ /// <throws> ReaderException if an error occurs or barcode cannot be found </throws>\r
+ public abstract Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints);\r
+ }\r
+}
\ No newline at end of file