-/*\r
+/*\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
* See the License for the specific language governing permissions and\r
* limitations under the License.\r
*/\r
+using System;\r
+using BarcodeFormat = com.google.zxing.BarcodeFormat;\r
+using ReaderException = com.google.zxing.ReaderException;\r
+using Result = com.google.zxing.Result;\r
+using ResultPoint = com.google.zxing.ResultPoint;\r
+using BitArray = com.google.zxing.common.BitArray;\r
namespace com.google.zxing.oned\r
-{ \r
- using System;\r
- using System.Text;\r
- using com.google.zxing.common;\r
-\r
-\r
- public sealed class Code128Reader : AbstractOneDReader\r
- { \r
- private static int[][] CODE_PATTERNS = new int[][]{\r
- new int[]{2, 1, 2, 2, 2, 2}, // 0\r
- new int[]{2, 2, 2, 1, 2, 2},\r
- new int[]{2, 2, 2, 2, 2, 1},\r
- new int[]{1, 2, 1, 2, 2, 3},\r
- new int[]{1, 2, 1, 3, 2, 2},\r
- new int[]{1, 3, 1, 2, 2, 2}, // 5\r
- new int[]{1, 2, 2, 2, 1, 3},\r
- new int[]{1, 2, 2, 3, 1, 2},\r
- new int[]{1, 3, 2, 2, 1, 2},\r
- new int[]{2, 2, 1, 2, 1, 3},\r
- new int[]{2, 2, 1, 3, 1, 2}, // 10\r
- new int[]{2, 3, 1, 2, 1, 2},\r
- new int[]{1, 1, 2, 2, 3, 2},\r
- new int[]{1, 2, 2, 1, 3, 2},\r
- new int[]{1, 2, 2, 2, 3, 1},\r
- new int[]{1, 1, 3, 2, 2, 2}, // 15\r
- new int[]{1, 2, 3, 1, 2, 2},\r
- new int[]{1, 2, 3, 2, 2, 1},\r
- new int[]{2, 2, 3, 2, 1, 1},\r
- new int[]{2, 2, 1, 1, 3, 2},\r
- new int[]{2, 2, 1, 2, 3, 1}, // 20\r
- new int[]{2, 1, 3, 2, 1, 2},\r
- new int[]{2, 2, 3, 1, 1, 2},\r
- new int[]{3, 1, 2, 1, 3, 1},\r
- new int[]{3, 1, 1, 2, 2, 2},\r
- new int[]{3, 2, 1, 1, 2, 2}, // 25\r
- new int[]{3, 2, 1, 2, 2, 1},\r
- new int[]{3, 1, 2, 2, 1, 2},\r
- new int[]{3, 2, 2, 1, 1, 2},\r
- new int[]{3, 2, 2, 2, 1, 1},\r
- new int[]{2, 1, 2, 1, 2, 3}, // 30\r
- new int[]{2, 1, 2, 3, 2, 1},\r
- new int[]{2, 3, 2, 1, 2, 1},\r
- new int[]{1, 1, 1, 3, 2, 3},\r
- new int[]{1, 3, 1, 1, 2, 3},\r
- new int[]{1, 3, 1, 3, 2, 1}, // 35\r
- new int[]{1, 1, 2, 3, 1, 3},\r
- new int[]{1, 3, 2, 1, 1, 3},\r
- new int[]{1, 3, 2, 3, 1, 1},\r
- new int[]{2, 1, 1, 3, 1, 3},\r
- new int[]{2, 3, 1, 1, 1, 3}, // 40\r
- new int[]{2, 3, 1, 3, 1, 1},\r
- new int[]{1, 1, 2, 1, 3, 3},\r
- new int[]{1, 1, 2, 3, 3, 1},\r
- new int[]{1, 3, 2, 1, 3, 1},\r
- new int[]{1, 1, 3, 1, 2, 3}, // 45\r
- new int[]{1, 1, 3, 3, 2, 1},\r
- new int[]{1, 3, 3, 1, 2, 1},\r
- new int[]{3, 1, 3, 1, 2, 1},\r
- new int[]{2, 1, 1, 3, 3, 1},\r
- new int[]{2, 3, 1, 1, 3, 1}, // 50\r
- new int[]{2, 1, 3, 1, 1, 3},\r
- new int[]{2, 1, 3, 3, 1, 1},\r
- new int[]{2, 1, 3, 1, 3, 1},\r
- new int[]{3, 1, 1, 1, 2, 3},\r
- new int[]{3, 1, 1, 3, 2, 1}, // 55\r
- new int[]{3, 3, 1, 1, 2, 1},\r
- new int[]{3, 1, 2, 1, 1, 3},\r
- new int[]{3, 1, 2, 3, 1, 1},\r
- new int[]{3, 3, 2, 1, 1, 1},\r
- new int[]{3, 1, 4, 1, 1, 1}, // 60\r
- new int[]{2, 2, 1, 4, 1, 1},\r
- new int[]{4, 3, 1, 1, 1, 1},\r
- new int[]{1, 1, 1, 2, 2, 4},\r
- new int[]{1, 1, 1, 4, 2, 2},\r
- new int[] {1, 2, 1, 1, 2, 4}, // 65\r
- new int[]{1, 2, 1, 4, 2, 1},\r
- new int[]{1, 4, 1, 1, 2, 2},\r
- new int[]{1, 4, 1, 2, 2, 1},\r
- new int[]{1, 1, 2, 2, 1, 4},\r
- new int[]{1, 1, 2, 4, 1, 2}, // 70\r
- new int[]{1, 2, 2, 1, 1, 4},\r
- new int[]{1, 2, 2, 4, 1, 1},\r
- new int[]{1, 4, 2, 1, 1, 2},\r
- new int[]{1, 4, 2, 2, 1, 1},\r
- new int[]{2, 4, 1, 2, 1, 1}, // 75\r
- new int[]{2, 2, 1, 1, 1, 4},\r
- new int[]{4, 1, 3, 1, 1, 1},\r
- new int[]{2, 4, 1, 1, 1, 2},\r
- new int[]{1, 3, 4, 1, 1, 1},\r
- new int[]{1, 1, 1, 2, 4, 2}, // 80\r
- new int[]{1, 2, 1, 1, 4, 2},\r
- new int[]{1, 2, 1, 2, 4, 1},\r
- new int[]{1, 1, 4, 2, 1, 2},\r
- new int[]{1, 2, 4, 1, 1, 2},\r
- new int[]{1, 2, 4, 2, 1, 1}, // 85\r
- new int[]{4, 1, 1, 2, 1, 2},\r
- new int[]{4, 2, 1, 1, 1, 2},\r
- new int[]{4, 2, 1, 2, 1, 1},\r
- new int[]{2, 1, 2, 1, 4, 1},\r
- new int[]{2, 1, 4, 1, 2, 1}, // 90\r
- new int[]{4, 1, 2, 1, 2, 1},\r
- new int[]{1, 1, 1, 1, 4, 3},\r
- new int[]{1, 1, 1, 3, 4, 1},\r
- new int[]{1, 3, 1, 1, 4, 1},\r
- new int[]{1, 1, 4, 1, 1, 3}, // 95\r
- new int[]{1, 1, 4, 3, 1, 1},\r
- new int[]{4, 1, 1, 1, 1, 3},\r
- new int[]{4, 1, 1, 3, 1, 1},\r
- new int[]{1, 1, 3, 1, 4, 1},\r
- new int[]{1, 1, 4, 1, 3, 1}, // 100\r
- new int[]{3, 1, 1, 1, 4, 1},\r
- new int[]{4, 1, 1, 1, 3, 1},\r
- new int[]{2, 1, 1, 4, 1, 2},\r
- new int[]{2, 1, 1, 2, 1, 4},\r
- new int[]{2, 1, 1, 2, 3, 2}, // 105\r
- new int[]{2, 3, 3, 1, 1, 1, 2}\r
- };\r
-\r
- private static int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25f);\r
- private static int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);\r
-\r
- private const int CODE_SHIFT = 98;\r
-\r
- private const int CODE_CODE_C = 99;\r
- private const int CODE_CODE_B = 100;\r
- private const int CODE_CODE_A = 101;\r
-\r
- private const int CODE_FNC_1 = 102;\r
- private const int CODE_FNC_2 = 97;\r
- private const int CODE_FNC_3 = 96;\r
- private const int CODE_FNC_4_A = 101;\r
- private const int CODE_FNC_4_B = 100;\r
-\r
- private const int CODE_START_A = 103;\r
- private const int CODE_START_B = 104;\r
- private const int CODE_START_C = 105;\r
- private const int CODE_STOP = 106;\r
-\r
- private static int[] findStartPattern(BitArray row) {\r
- int width = row.getSize();\r
- int rowOffset = 0;\r
- while (rowOffset < width) {\r
- if (row.get(rowOffset)) {\r
- break;\r
- }\r
- rowOffset++;\r
- }\r
-\r
- int counterPosition = 0;\r
- int[] counters = new int[6];\r
- int patternStart = rowOffset;\r
- bool isWhite = false;\r
- int patternLength = counters.Length;\r
-\r
- for (int i = rowOffset; i < width; i++) {\r
- bool pixel = row.get(i);\r
- if ((!pixel && isWhite) || (pixel && !isWhite)) {\r
- counters[counterPosition]++;\r
- } else {\r
- if (counterPosition == patternLength - 1) {\r
- int bestVariance = MAX_AVG_VARIANCE;\r
- int bestMatch = -1;\r
- for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) {\r
- int variance = patternMatchVariance(counters, CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE);\r
- if (variance < bestVariance) {\r
- bestVariance = variance;\r
- bestMatch = startCode;\r
- }\r
- }\r
- if (bestMatch >= 0) {\r
- // Look for whitespace before start pattern, >= 50% of width of start pattern \r
- if (row.isRange(Math.Max(0, patternStart - (i - patternStart) / 2), patternStart, false)) {\r
- return new int[]{patternStart, i, bestMatch};\r
- }\r
- }\r
- patternStart += counters[0] + counters[1];\r
- for (int y = 2; y < patternLength; y++) {\r
- counters[y - 2] = counters[y];\r
- }\r
- counters[patternLength - 2] = 0;\r
- counters[patternLength - 1] = 0;\r
- counterPosition--;\r
- } else {\r
- counterPosition++;\r
- }\r
- counters[counterPosition] = 1;\r
- isWhite = !isWhite;\r
- }\r
- }\r
- throw new ReaderException();\r
- }\r
-\r
- private static int decodeCode(BitArray row, int[] counters, int rowOffset) {\r
- recordPattern(row, rowOffset, counters);\r
- int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept\r
- int bestMatch = -1;\r
- for (int d = 0; d < CODE_PATTERNS.Length; d++) {\r
- int[] pattern = CODE_PATTERNS[d];\r
- int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);\r
- if (variance < bestVariance) {\r
- bestVariance = variance;\r
- bestMatch = d;\r
- }\r
- }\r
- // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6\r
- if (bestMatch >= 0) {\r
- return bestMatch;\r
- } else {\r
- throw new ReaderException();\r
- }\r
- }\r
-\r
- public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) {\r
-\r
- int[] startPatternInfo = findStartPattern(row);\r
- int startCode = startPatternInfo[2];\r
- int codeSet;\r
- switch (startCode) {\r
- case CODE_START_A:\r
- codeSet = CODE_CODE_A;\r
- break;\r
- case CODE_START_B:\r
- codeSet = CODE_CODE_B;\r
- break;\r
- case CODE_START_C:\r
- codeSet = CODE_CODE_C;\r
- break;\r
- default:\r
- throw new ReaderException();\r
- }\r
-\r
- bool done = false;\r
- bool isNextShifted = false;\r
-\r
- StringBuilder result = new StringBuilder();\r
- int lastStart = startPatternInfo[0];\r
- int nextStart = startPatternInfo[1];\r
- int[] counters = new int[6];\r
-\r
- int lastCode = 0;\r
- int code = 0;\r
- int checksumTotal = startCode;\r
- int multiplier = 0;\r
- bool lastCharacterWasPrintable = true;\r
-\r
- while (!done) {\r
-\r
- bool unshift = isNextShifted;\r
- isNextShifted = false;\r
-\r
- // Save off last code\r
- lastCode = code;\r
-\r
- // Decode another code from image\r
- code = decodeCode(row, counters, nextStart);\r
-\r
- // Remember whether the last code was printable or not (excluding CODE_STOP)\r
- if (code != CODE_STOP) {\r
- lastCharacterWasPrintable = true;\r
- }\r
-\r
- // Add to checksum computation (if not CODE_STOP of course)\r
- if (code != CODE_STOP) {\r
- multiplier++;\r
- checksumTotal += multiplier * code;\r
- }\r
-\r
- // Advance to where the next code will to start\r
- lastStart = nextStart;\r
- for (int i = 0; i < counters.Length; i++) {\r
- nextStart += counters[i];\r
- }\r
-\r
- // Take care of illegal start codes\r
- switch (code) {\r
- case CODE_START_A:\r
- case CODE_START_B:\r
- case CODE_START_C:\r
- throw new ReaderException();\r
- }\r
-\r
- switch (codeSet) {\r
-\r
- case CODE_CODE_A:\r
- if (code < 64) {\r
- result.Append((char) (' ' + code));\r
- } else if (code < 96) {\r
- result.Append((char) (code - 64));\r
- } else {\r
- // Don't let CODE_STOP, which always appears, affect whether whether we think the last code\r
- // was printable or not\r
- if (code != CODE_STOP) {\r
- lastCharacterWasPrintable = false;\r
- }\r
- switch (code) {\r
- case CODE_FNC_1:\r
- case CODE_FNC_2:\r
- case CODE_FNC_3:\r
- case CODE_FNC_4_A:\r
- // do nothing?\r
- break;\r
- case CODE_SHIFT:\r
- isNextShifted = true;\r
- codeSet = CODE_CODE_B;\r
- break;\r
- case CODE_CODE_B:\r
- codeSet = CODE_CODE_B;\r
- break;\r
- case CODE_CODE_C:\r
- codeSet = CODE_CODE_C;\r
- break;\r
- case CODE_STOP:\r
- done = true;\r
- break;\r
- }\r
- }\r
- break;\r
- case CODE_CODE_B:\r
- if (code < 96) {\r
- result.Append((char) (' ' + code));\r
- } else {\r
- if (code != CODE_STOP) {\r
- lastCharacterWasPrintable = false;\r
- }\r
- switch (code) {\r
- case CODE_FNC_1:\r
- case CODE_FNC_2:\r
- case CODE_FNC_3:\r
- case CODE_FNC_4_B:\r
- // do nothing?\r
- break;\r
- case CODE_SHIFT:\r
- isNextShifted = true;\r
- codeSet = CODE_CODE_C;\r
- break;\r
- case CODE_CODE_A:\r
- codeSet = CODE_CODE_A;\r
- break;\r
- case CODE_CODE_C:\r
- codeSet = CODE_CODE_C;\r
- break;\r
- case CODE_STOP:\r
- done = true;\r
- break;\r
- }\r
- }\r
- break;\r
- case CODE_CODE_C:\r
- if (code < 100) {\r
- if (code < 10) {\r
- result.Append('0');\r
- }\r
- result.Append(code);\r
- } else {\r
- if (code != CODE_STOP) {\r
- lastCharacterWasPrintable = false;\r
- }\r
- switch (code) {\r
- case CODE_FNC_1:\r
- // do nothing?\r
- break;\r
- case CODE_CODE_A:\r
- codeSet = CODE_CODE_A;\r
- break;\r
- case CODE_CODE_B:\r
- codeSet = CODE_CODE_B;\r
- break;\r
- case CODE_STOP:\r
- done = true;\r
- break;\r
- }\r
- }\r
- break;\r
- }\r
-\r
- // Unshift back to another code set if we were shifted\r
- if (unshift) {\r
- switch (codeSet) {\r
- case CODE_CODE_A:\r
- codeSet = CODE_CODE_C;\r
- break;\r
- case CODE_CODE_B:\r
- codeSet = CODE_CODE_A;\r
- break;\r
- case CODE_CODE_C:\r
- codeSet = CODE_CODE_B;\r
- break;\r
- }\r
- }\r
-\r
- }\r
-\r
- // Check for ample whitespice following pattern, but, to do this we first need to remember that we\r
- // fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left to read off.\r
- // Would be slightly better to properly read. Here we just skip it:\r
- while (row.get(nextStart)) {\r
- nextStart++;\r
- }\r
- if (!row.isRange(nextStart, Math.Min(row.getSize(), nextStart + (nextStart - lastStart) / 2), false)) {\r
- throw new ReaderException();\r
- }\r
-\r
- // Pull out from sum the value of the penultimate check code\r
- checksumTotal -= multiplier * lastCode;\r
- // lastCode is the checksum then:\r
- if (checksumTotal % 103 != lastCode) {\r
- throw new ReaderException();\r
- }\r
-\r
- // Need to pull out the check digits from string\r
- int resultLength = result.Length;\r
- // Only bother if, well, the result had at least one character, and if the checksum digit happened\r
- // to be a printable character. If it was just interpreted as a control code, nothing to remove\r
- if (resultLength > 0 && lastCharacterWasPrintable) {\r
- if (codeSet == CODE_CODE_C) {\r
- result.Remove(resultLength - 2, 2);\r
- } else {\r
- result.Remove(resultLength - 1, 1);\r
- }\r
- }\r
-\r
- String resultString = result.ToString();\r
-\r
- if (resultString.Length == 0) {\r
- // Almost surely a false positive\r
- throw new ReaderException();\r
- }\r
-\r
- float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f;\r
- float right = (float) (nextStart + lastStart) / 2.0f;\r
- return new Result(\r
- resultString,\r
- null,\r
- new ResultPoint[]{\r
- new GenericResultPoint(left, (float) rowNumber),\r
- new GenericResultPoint(right, (float) rowNumber)},\r
- BarcodeFormat.CODE_128);\r
-\r
- }\r
- \r
- }\r
-\r
-\r
-\r
-}\r
+{\r
+ \r
+ /// <summary> <p>Decodes Code 128 barcodes.</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 Code128Reader:OneDReader\r
+ {\r
+ \r
+ //UPGRADE_NOTE: Final was removed from the declaration of 'CODE_PATTERNS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
+ private static readonly int[][] CODE_PATTERNS = new int[][]{new int[]{2, 1, 2, 2, 2, 2}, new int[]{2, 2, 2, 1, 2, 2}, new int[]{2, 2, 2, 2, 2, 1}, new int[]{1, 2, 1, 2, 2, 3}, new int[]{1, 2, 1, 3, 2, 2}, new int[]{1, 3, 1, 2, 2, 2}, new int[]{1, 2, 2, 2, 1, 3}, new int[]{1, 2, 2, 3, 1, 2}, new int[]{1, 3, 2, 2, 1, 2}, new int[]{2, 2, 1, 2, 1, 3}, new int[]{2, 2, 1, 3, 1, 2}, new int[]{2, 3, 1, 2, 1, 2}, new int[]{1, 1, 2, 2, 3, 2}, new int[]{1, 2, 2, 1, 3, 2}, new int[]{1, 2, 2, 2, 3, 1}, new int[]{1, 1, 3, 2, 2, 2}, new int[]{1, 2, 3, 1, 2, 2}, new int[]{1, 2, 3, 2, 2, 1}, new int[]{2, 2, 3, 2, 1, 1}, new int[]{2, 2, 1, 1, 3, 2}, new int[]{2, 2, 1, 2, 3, 1}, new int[]{2, 1, 3, 2, 1, 2}, new int[]{2, 2, 3, 1, 1, 2}, new int[]{3, 1, 2, 1, 3, 1}, new int[]{3, 1, 1, 2, 2, 2}, new int[]{3, 2, 1, 1, 2, 2}, new int[]{3, 2, 1, 2, 2, 1}, new int[]{3, 1, 2, 2, 1, 2}, new int[]{3, 2, 2, 1, 1, 2}, new int[]{3, 2, 2, 2, 1, 1}, new int[]{2, 1, 2, 1, 2, 3}, new int[]{2, 1, 2, 3, 2, 1}, new int[]{2, 3, 2, 1, 2, 1}, new int[]{1, 1, 1, 3, 2, 3}, new int[]{1, 3, 1, 1, 2, 3}, new int[]{1, 3, 1, 3, 2, 1}, new int[]{1, 1, 2, 3, 1, 3}, new int[]{1, 3, 2, 1, 1, 3}, new int[]{1, 3, 2, 3, 1, 1}, new int[]{2, 1, 1, 3, 1, 3}, new int[]{2, 3, 1, 1, 1, 3}, new int[]{2, 3, 1, 3, 1, 1}, new int[]{1, 1, 2, 1, 3, 3}, new int[]{1, 1, 2, 3, 3, 1}, new int[]{1, 3, 2, 1, 3, 1}, new int[]{1, 1, 3, 1, 2, 3}, new int[]{1, 1, 3, 3, 2, 1}, new int[]{1, 3, 3, 1, 2, 1}, new int[]{3, 1, 3, 1, 2, 1}, new int[]{2, 1, 1, 3, 3, 1}, new int[]{2, 3, 1, 1, 3, 1}, new int[]{2, 1, 3, 1, 1, 3}, new int[]{2, 1, 3, 3, 1, 1}, new int[]{2, 1, 3, 1, 3, 1}, new int[]{3, 1, 1, 1, 2, 3}, new int[]{3, 1, 1, 3, 2, 1}, new int[]{3, 3, 1, 1, 2, 1}, new int[]{3, 1, 2, 1, 1, 3}, new int[]{3, 1, 2, 3, 1, 1}, new int[]{3, 3, 2, 1, 1, 1}, new int[]{3, 1, 4, 1, 1, 1}, new int[]{2, 2, 1, 4, 1, 1}, new int[]{4, 3, 1, 1, 1, 1}, new int[]{1, 1, 1, 2, 2, 4}, new int[]{1, 1, 1, 4, 2, 2}, new int[]{1, 2, 1, 1, 2, 4}, new int[]{1, 2, 1, 4, 2, 1}, new int[]{1, 4, 1, 1, 2, 2}, new \r
+ int[]{1, 4, 1, 2, 2, 1}, new int[]{1, 1, 2, 2, 1, 4}, new int[]{1, 1, 2, 4, 1, 2}, new int[]{1, 2, 2, 1, 1, 4}, new int[]{1, 2, 2, 4, 1, 1}, new int[]{1, 4, 2, 1, 1, 2}, new int[]{1, 4, 2, 2, 1, 1}, new int[]{2, 4, 1, 2, 1, 1}, new int[]{2, 2, 1, 1, 1, 4}, new int[]{4, 1, 3, 1, 1, 1}, new int[]{2, 4, 1, 1, 1, 2}, new int[]{1, 3, 4, 1, 1, 1}, new int[]{1, 1, 1, 2, 4, 2}, new int[]{1, 2, 1, 1, 4, 2}, new int[]{1, 2, 1, 2, 4, 1}, new int[]{1, 1, 4, 2, 1, 2}, new int[]{1, 2, 4, 1, 1, 2}, new int[]{1, 2, 4, 2, 1, 1}, new int[]{4, 1, 1, 2, 1, 2}, new int[]{4, 2, 1, 1, 1, 2}, new int[]{4, 2, 1, 2, 1, 1}, new int[]{2, 1, 2, 1, 4, 1}, new int[]{2, 1, 4, 1, 2, 1}, new int[]{4, 1, 2, 1, 2, 1}, new int[]{1, 1, 1, 1, 4, 3}, new int[]{1, 1, 1, 3, 4, 1}, new int[]{1, 3, 1, 1, 4, 1}, new int[]{1, 1, 4, 1, 1, 3}, new int[]{1, 1, 4, 3, 1, 1}, new int[]{4, 1, 1, 1, 1, 3}, new int[]{4, 1, 1, 3, 1, 1}, new int[]{1, 1, 3, 1, 4, 1}, new int[]{1, 1, 4, 1, 3, 1}, new int[]{3, 1, 1, 1, 4, 1}, new int[]{4, 1, 1, 1, 3, 1}, new int[]{2, 1, 1, 4, 1, 2}, new int[]{2, 1, 1, 2, 1, 4}, new int[]{2, 1, 1, 2, 3, 2}, new int[]{2, 3, 3, 1, 1, 1, 2}};\r
+ \r
+ //UPGRADE_NOTE: Final was removed from the declaration of 'MAX_AVG_VARIANCE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\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
+ private static readonly int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25f);\r
+ //UPGRADE_NOTE: Final was removed from the declaration of 'MAX_INDIVIDUAL_VARIANCE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\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
+ private static readonly int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);\r
+ \r
+ private const int CODE_SHIFT = 98;\r
+ \r
+ private const int CODE_CODE_C = 99;\r
+ private const int CODE_CODE_B = 100;\r
+ private const int CODE_CODE_A = 101;\r
+ \r
+ private const int CODE_FNC_1 = 102;\r
+ private const int CODE_FNC_2 = 97;\r
+ private const int CODE_FNC_3 = 96;\r
+ private const int CODE_FNC_4_A = 101;\r
+ private const int CODE_FNC_4_B = 100;\r
+ \r
+ private const int CODE_START_A = 103;\r
+ private const int CODE_START_B = 104;\r
+ private const int CODE_START_C = 105;\r
+ private const int CODE_STOP = 106;\r
+ \r
+ private static int[] findStartPattern(BitArray row)\r
+ {\r
+ int width = row.Size;\r
+ int rowOffset = 0;\r
+ while (rowOffset < width)\r
+ {\r
+ if (row.get_Renamed(rowOffset))\r
+ {\r
+ break;\r
+ }\r
+ rowOffset++;\r
+ }\r
+ \r
+ int counterPosition = 0;\r
+ int[] counters = new int[6];\r
+ int patternStart = rowOffset;\r
+ bool isWhite = false;\r
+ int patternLength = counters.Length;\r
+ \r
+ for (int i = rowOffset; i < width; i++)\r
+ {\r
+ bool pixel = row.get_Renamed(i);\r
+ if (pixel ^ isWhite)\r
+ {\r
+ counters[counterPosition]++;\r
+ }\r
+ else\r
+ {\r
+ if (counterPosition == patternLength - 1)\r
+ {\r
+ int bestVariance = MAX_AVG_VARIANCE;\r
+ int bestMatch = - 1;\r
+ for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++)\r
+ {\r
+ int variance = patternMatchVariance(counters, CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE);\r
+ if (variance < bestVariance)\r
+ {\r
+ bestVariance = variance;\r
+ bestMatch = startCode;\r
+ }\r
+ }\r
+ if (bestMatch >= 0)\r
+ {\r
+ // Look for whitespace before start pattern, >= 50% of width of start pattern\r
+ if (row.isRange(System.Math.Max(0, patternStart - (i - patternStart) / 2), patternStart, false))\r
+ {\r
+ return new int[]{patternStart, i, bestMatch};\r
+ }\r
+ }\r
+ patternStart += counters[0] + counters[1];\r
+ for (int y = 2; y < patternLength; y++)\r
+ {\r
+ counters[y - 2] = counters[y];\r
+ }\r
+ counters[patternLength - 2] = 0;\r
+ counters[patternLength - 1] = 0;\r
+ counterPosition--;\r
+ }\r
+ else\r
+ {\r
+ counterPosition++;\r
+ }\r
+ counters[counterPosition] = 1;\r
+ isWhite = !isWhite;\r
+ }\r
+ }\r
+ throw ReaderException.Instance;\r
+ }\r
+ \r
+ private static int decodeCode(BitArray row, int[] counters, int rowOffset)\r
+ {\r
+ recordPattern(row, rowOffset, counters);\r
+ int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept\r
+ int bestMatch = - 1;\r
+ for (int d = 0; d < CODE_PATTERNS.Length; d++)\r
+ {\r
+ int[] pattern = CODE_PATTERNS[d];\r
+ int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);\r
+ if (variance < bestVariance)\r
+ {\r
+ bestVariance = variance;\r
+ bestMatch = d;\r
+ }\r
+ }\r
+ // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6.\r
+ if (bestMatch >= 0)\r
+ {\r
+ return bestMatch;\r
+ }\r
+ else\r
+ {\r
+ throw ReaderException.Instance;\r
+ }\r
+ }\r
+ \r
+ public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints)\r
+ {\r
+ \r
+ int[] startPatternInfo = findStartPattern(row);\r
+ int startCode = startPatternInfo[2];\r
+ int codeSet;\r
+ switch (startCode)\r
+ {\r
+ \r
+ case CODE_START_A: \r
+ codeSet = CODE_CODE_A;\r
+ break;\r
+ \r
+ case CODE_START_B: \r
+ codeSet = CODE_CODE_B;\r
+ break;\r
+ \r
+ case CODE_START_C: \r
+ codeSet = CODE_CODE_C;\r
+ break;\r
+ \r
+ default: \r
+ throw ReaderException.Instance;\r
+ \r
+ }\r
+ \r
+ bool done = false;\r
+ bool isNextShifted = false;\r
+ \r
+ System.Text.StringBuilder result = new System.Text.StringBuilder(20);\r
+ int lastStart = startPatternInfo[0];\r
+ int nextStart = startPatternInfo[1];\r
+ int[] counters = new int[6];\r
+ \r
+ int lastCode = 0;\r
+ int code = 0;\r
+ int checksumTotal = startCode;\r
+ int multiplier = 0;\r
+ bool lastCharacterWasPrintable = true;\r
+ \r
+ while (!done)\r
+ {\r
+ \r
+ bool unshift = isNextShifted;\r
+ isNextShifted = false;\r
+ \r
+ // Save off last code\r
+ lastCode = code;\r
+ \r
+ // Decode another code from image\r
+ code = decodeCode(row, counters, nextStart);\r
+ \r
+ // Remember whether the last code was printable or not (excluding CODE_STOP)\r
+ if (code != CODE_STOP)\r
+ {\r
+ lastCharacterWasPrintable = true;\r
+ }\r
+ \r
+ // Add to checksum computation (if not CODE_STOP of course)\r
+ if (code != CODE_STOP)\r
+ {\r
+ multiplier++;\r
+ checksumTotal += multiplier * code;\r
+ }\r
+ \r
+ // Advance to where the next code will to start\r
+ lastStart = nextStart;\r
+ for (int i = 0; i < counters.Length; i++)\r
+ {\r
+ nextStart += counters[i];\r
+ }\r
+ \r
+ // Take care of illegal start codes\r
+ switch (code)\r
+ {\r
+ \r
+ case CODE_START_A: \r
+ case CODE_START_B: \r
+ case CODE_START_C: \r
+ throw ReaderException.Instance;\r
+ }\r
+ \r
+ switch (codeSet)\r
+ {\r
+ \r
+ \r
+ case CODE_CODE_A: \r
+ if (code < 64)\r
+ {\r
+ result.Append((char) (' ' + code));\r
+ }\r
+ else if (code < 96)\r
+ {\r
+ result.Append((char) (code - 64));\r
+ }\r
+ else\r
+ {\r
+ // Don't let CODE_STOP, which always appears, affect whether whether we think the last\r
+ // code was printable or not.\r
+ if (code != CODE_STOP)\r
+ {\r
+ lastCharacterWasPrintable = false;\r
+ }\r
+ switch (code)\r
+ {\r
+ \r
+ case CODE_FNC_1: \r
+ case CODE_FNC_2: \r
+ case CODE_FNC_3: \r
+ case CODE_FNC_4_A: \r
+ // do nothing?\r
+ break;\r
+ \r
+ case CODE_SHIFT: \r
+ isNextShifted = true;\r
+ codeSet = CODE_CODE_B;\r
+ break;\r
+ \r
+ case CODE_CODE_B: \r
+ codeSet = CODE_CODE_B;\r
+ break;\r
+ \r
+ case CODE_CODE_C: \r
+ codeSet = CODE_CODE_C;\r
+ break;\r
+ \r
+ case CODE_STOP: \r
+ done = true;\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+ \r
+ case CODE_CODE_B: \r
+ if (code < 96)\r
+ {\r
+ result.Append((char) (' ' + code));\r
+ }\r
+ else\r
+ {\r
+ if (code != CODE_STOP)\r
+ {\r
+ lastCharacterWasPrintable = false;\r
+ }\r
+ switch (code)\r
+ {\r
+ \r
+ case CODE_FNC_1: \r
+ case CODE_FNC_2: \r
+ case CODE_FNC_3: \r
+ case CODE_FNC_4_B: \r
+ // do nothing?\r
+ break;\r
+ \r
+ case CODE_SHIFT: \r
+ isNextShifted = true;\r
+ codeSet = CODE_CODE_C;\r
+ break;\r
+ \r
+ case CODE_CODE_A: \r
+ codeSet = CODE_CODE_A;\r
+ break;\r
+ \r
+ case CODE_CODE_C: \r
+ codeSet = CODE_CODE_C;\r
+ break;\r
+ \r
+ case CODE_STOP: \r
+ done = true;\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+ \r
+ case CODE_CODE_C: \r
+ if (code < 100)\r
+ {\r
+ if (code < 10)\r
+ {\r
+ result.Append('0');\r
+ }\r
+ result.Append(code);\r
+ }\r
+ else\r
+ {\r
+ if (code != CODE_STOP)\r
+ {\r
+ lastCharacterWasPrintable = false;\r
+ }\r
+ switch (code)\r
+ {\r
+ \r
+ case CODE_FNC_1: \r
+ // do nothing?\r
+ break;\r
+ \r
+ case CODE_CODE_A: \r
+ codeSet = CODE_CODE_A;\r
+ break;\r
+ \r
+ case CODE_CODE_B: \r
+ codeSet = CODE_CODE_B;\r
+ break;\r
+ \r
+ case CODE_STOP: \r
+ done = true;\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ \r
+ // Unshift back to another code set if we were shifted\r
+ if (unshift)\r
+ {\r
+ switch (codeSet)\r
+ {\r
+ \r
+ case CODE_CODE_A: \r
+ codeSet = CODE_CODE_C;\r
+ break;\r
+ \r
+ case CODE_CODE_B: \r
+ codeSet = CODE_CODE_A;\r
+ break;\r
+ \r
+ case CODE_CODE_C: \r
+ codeSet = CODE_CODE_B;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ \r
+ // Check for ample whitespace following pattern, but, to do this we first need to remember that\r
+ // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left\r
+ // to read off. Would be slightly better to properly read. Here we just skip it:\r
+ int width = row.Size;\r
+ while (nextStart < width && row.get_Renamed(nextStart))\r
+ {\r
+ nextStart++;\r
+ }\r
+ if (!row.isRange(nextStart, System.Math.Min(width, nextStart + (nextStart - lastStart) / 2), false))\r
+ {\r
+ throw ReaderException.Instance;\r
+ }\r
+ \r
+ // Pull out from sum the value of the penultimate check code\r
+ checksumTotal -= multiplier * lastCode;\r
+ // lastCode is the checksum then:\r
+ if (checksumTotal % 103 != lastCode)\r
+ {\r
+ throw ReaderException.Instance;\r
+ }\r
+ \r
+ // Need to pull out the check digits from string\r
+ int resultLength = result.Length;\r
+ // Only bother if the result had at least one character, and if the checksum digit happened to\r
+ // be a printable character. If it was just interpreted as a control code, nothing to remove.\r
+ if (resultLength > 0 && lastCharacterWasPrintable)\r
+ {\r
+ if (codeSet == CODE_CODE_C)\r
+ {\r
+ result.Remove(resultLength - 2, resultLength - (resultLength - 2));\r
+ }\r
+ else\r
+ {\r
+ result.Remove(resultLength - 1, resultLength - (resultLength - 1));\r
+ }\r
+ }\r
+ \r
+ System.String resultString = result.ToString();\r
+ \r
+ if (resultString.Length == 0)\r
+ {\r
+ // Almost surely a false positive\r
+ throw ReaderException.Instance;\r
+ }\r
+ \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
+ float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f;\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
+ float right = (float) (nextStart + lastStart) / 2.0f;\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
+ return new Result(resultString, null, new ResultPoint[]{new ResultPoint(left, (float) rowNumber), new ResultPoint(right, (float) rowNumber)}, BarcodeFormat.CODE_128);\r
+ }\r
+ }\r
+}
\ No newline at end of file