private static int[] findAsteriskPattern(BitArray row) { int width = row.Size; int rowOffset = 0; while (rowOffset < width) { if (row.get_Renamed(rowOffset)) { break; } rowOffset++; } int counterPosition = 0; int[] counters = new int[9]; int patternStart = rowOffset; bool isWhite = false; int patternLength = counters.Length; for (int i = rowOffset; i < width; i++) { bool pixel = row.get_Renamed(i); if (pixel ^ isWhite) { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { if (toNarrowWidePattern(counters) == ASTERISK_ENCODING) { // Look for whitespace before start pattern, >= 50% of width of start pattern if (row.isRange(System.Math.Max(0, patternStart - (i - patternStart) / 2), patternStart, false)) { return(new int[] { patternStart, i }); } } patternStart += counters[0] + counters[1]; for (int y = 2; y < patternLength; y++) { counters[y - 2] = counters[y]; } counters[patternLength - 2] = 0; counters[patternLength - 1] = 0; counterPosition--; } else { counterPosition++; } counters[counterPosition] = 1; isWhite = !isWhite; } } throw ReaderException.Instance; }
/// <param name="row">row of black/white values to search /// </param> /// <param name="rowOffset">position to start search /// </param> /// <param name="whiteFirst">if true, indicates that the pattern specifies white/black/white/... /// pixel counts, otherwise, it is interpreted as black/white/black/... /// </param> /// <param name="pattern">pattern of counts of number of black and white pixels that are being /// searched for as a pattern /// </param> /// <returns> start/end horizontal offset of guard pattern, as an array of two ints /// </returns> /// <throws> ReaderException if pattern is not found </throws> internal static int[] findGuardPattern(BitArray row, int rowOffset, bool whiteFirst, int[] pattern) { int patternLength = pattern.Length; int[] counters = new int[patternLength]; int width = row.Size; bool isWhite = false; while (rowOffset < width) { isWhite = !row.get_Renamed(rowOffset); if (whiteFirst == isWhite) { break; } rowOffset++; } int counterPosition = 0; int patternStart = rowOffset; for (int x = rowOffset; x < width; x++) { bool pixel = row.get_Renamed(x); if (pixel ^ isWhite) { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { return(new int[] { patternStart, x }); } patternStart += counters[0] + counters[1]; for (int y = 2; y < patternLength; y++) { counters[y - 2] = counters[y]; } counters[patternLength - 2] = 0; counters[patternLength - 1] = 0; counterPosition--; } else { counterPosition++; } counters[counterPosition] = 1; isWhite = !isWhite; } } throw ReaderException.Instance; }
/// <summary> Records the size of successive runs of white and black pixels in a row, starting at a given point. /// The values are recorded in the given array, and the number of runs recorded is equal to the size /// of the array. If the row starts on a white pixel at the given start point, then the first count /// recorded is the run of white pixels starting from that point; likewise it is the count of a run /// of black pixels if the row begin on a black pixels at that point. /// /// </summary> /// <param name="row">row to count from /// </param> /// <param name="start">offset into row to start at /// </param> /// <param name="counters">array into which to record counts /// </param> /// <throws> ReaderException if counters cannot be filled entirely from row before running out </throws> /// <summary> of pixels /// </summary> internal static void recordPattern(BitArray row, int start, int[] counters) { int numCounters = counters.Length; for (int i = 0; i < numCounters; i++) { counters[i] = 0; } int end = row.Size; if (start >= end) { throw ReaderException.Instance; } bool isWhite = !row.get_Renamed(start); int counterPosition = 0; int i2 = start; while (i2 < end) { bool pixel = row.get_Renamed(i2); if (pixel ^ isWhite) { // that is, exactly one is true counters[counterPosition]++; } else { counterPosition++; if (counterPosition == numCounters) { break; } else { counters[counterPosition] = 1; isWhite ^= true; // isWhite = !isWhite; } } i2++; } // If we read fully the last section of pixels and filled up our counters -- or filled // the last counter but ran off the side of the image, OK. Otherwise, a problem. if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i2 == end))) { throw ReaderException.Instance; } }
/// <param name="row"> row of black/white values to search /// </param> /// <param name="rowOffset">position to start search /// </param> /// <param name="pattern"> pattern of counts of number of black and white pixels that are /// being searched for as a pattern /// </param> /// <returns> start/end horizontal offset of guard pattern, as an array of two /// ints /// </returns> /// <throws> ReaderException if pattern is not found </throws> private static int[] findGuardPattern(BitArray row, int rowOffset, int[] pattern) { // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be // merged to a single method. int patternLength = pattern.Length; int[] counters = new int[patternLength]; int width = row.Size; bool isWhite = false; int counterPosition = 0; int patternStart = rowOffset; for (int x = rowOffset; x < width; x++) { bool pixel = row.get_Renamed(x); if (pixel ^ isWhite) { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { return(new int[] { patternStart, x }); } patternStart += counters[0] + counters[1]; for (int y = 2; y < patternLength; y++) { counters[y - 2] = counters[y]; } counters[patternLength - 2] = 0; counters[patternLength - 1] = 0; counterPosition--; } else { counterPosition++; } counters[counterPosition] = 1; isWhite = !isWhite; } } throw ReaderException.Instance; }
/// <summary> The start & end patterns must be pre/post fixed by a quiet zone. This /// zone must be at least 10 times the width of a narrow line. Scan back until /// we either get to the start of the barcode or match the necessary number of /// quiet zone pixels. /// /// Note: Its assumed the row is reversed when using this method to find /// quiet zone after the end pattern. /// /// ref: http://www.barcode-1.net/i25code.html /// /// </summary> /// <param name="row">bit array representing the scanned barcode. /// </param> /// <param name="startPattern">index into row of the start or end pattern. /// </param> /// <throws> ReaderException if the quiet zone cannot be found, a ReaderException is thrown. </throws> private void validateQuietZone(BitArray row, int startPattern) { int quietCount = this.narrowLineWidth * 10; // expect to find this many pixels of quiet zone for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) { if (row.get_Renamed(i)) { break; } quietCount--; } if (quietCount != 0) { // Unable to find the necessary number of quiet zone pixels. throw ReaderException.Instance; } }
/// <summary> Skip all whitespace until we get to the first black line. /// /// </summary> /// <param name="row">row of black/white values to search /// </param> /// <returns> index of the first black line. /// </returns> /// <throws> ReaderException Throws exception if no black lines are found in the row </throws> private static int skipWhiteSpace(BitArray row) { int width = row.Size; int endStart = 0; while (endStart < width) { if (row.get_Renamed(endStart)) { break; } endStart++; } if (endStart == width) { throw ReaderException.Instance; } return(endStart); }
/// <summary> The start & end patterns must be pre/post fixed by a quiet zone. This /// zone must be at least 10 times the width of a narrow line. Scan back until /// we either get to the start of the barcode or match the necessary number of /// quiet zone pixels. /// /// Note: Its assumed the row is reversed when using this method to find /// quiet zone after the end pattern. /// /// ref: http://www.barcode-1.net/i25code.html /// /// </summary> /// <param name="row">bit array representing the scanned barcode. /// </param> /// <param name="startPattern">index into row of the start or end pattern. /// </param> /// <throws> ReaderException if the quiet zone cannot be found, a ReaderException is thrown. </throws> private void validateQuietZone(BitArray row, int startPattern) { int quietCount = this.narrowLineWidth * 10; // expect to find this many pixels of quiet zone for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) { if (row.get_Renamed(i)) { break; } quietCount--; } if (quietCount != 0) { // Unable to find the necessary number of quiet zone pixels. throw ReaderException.Instance; } }
/// <summary> Skip all whitespace until we get to the first black line. /// /// </summary> /// <param name="row">row of black/white values to search /// </param> /// <returns> index of the first black line. /// </returns> /// <throws> ReaderException Throws exception if no black lines are found in the row </throws> private static int skipWhiteSpace(BitArray row) { int width = row.Size; int endStart = 0; while (endStart < width) { if (row.get_Renamed(endStart)) { break; } endStart++; } if (endStart == width) { throw ReaderException.Instance; } return endStart; }
/// <param name="row"> row of black/white values to search /// </param> /// <param name="rowOffset">position to start search /// </param> /// <param name="pattern"> pattern of counts of number of black and white pixels that are /// being searched for as a pattern /// </param> /// <returns> start/end horizontal offset of guard pattern, as an array of two /// ints /// </returns> /// <throws> ReaderException if pattern is not found </throws> private static int[] findGuardPattern(BitArray row, int rowOffset, int[] pattern) { // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be // merged to a single method. int patternLength = pattern.Length; int[] counters = new int[patternLength]; int width = row.Size; bool isWhite = false; int counterPosition = 0; int patternStart = rowOffset; for (int x = rowOffset; x < width; x++) { bool pixel = row.get_Renamed(x); if (pixel ^ isWhite) { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { return new int[]{patternStart, x}; } patternStart += counters[0] + counters[1]; for (int y = 2; y < patternLength; y++) { counters[y - 2] = counters[y]; } counters[patternLength - 2] = 0; counters[patternLength - 1] = 0; counterPosition--; } else { counterPosition++; } counters[counterPosition] = 1; isWhite = !isWhite; } } throw ReaderException.Instance; }
public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) { int[] start = findAsteriskPattern(row); int nextStart = start[1]; int end = row.Size; // Read off white space while (nextStart < end && !row.get_Renamed(nextStart)) { nextStart++; } System.Text.StringBuilder result = new System.Text.StringBuilder(20); int[] counters = new int[9]; char decodedChar; int lastStart; do { recordPattern(row, nextStart, counters); int pattern = toNarrowWidePattern(counters); if (pattern < 0) { throw ReaderException.Instance; } decodedChar = patternToChar(pattern); result.Append(decodedChar); lastStart = nextStart; for (int i = 0; i < counters.Length; i++) { nextStart += counters[i]; } // Read off white space while (nextStart < end && !row.get_Renamed(nextStart)) { nextStart++; } }while (decodedChar != '*'); result.Remove(result.Length - 1, 1); // remove asterisk // Look for whitespace after pattern: int lastPatternSize = 0; for (int i = 0; i < counters.Length; i++) { lastPatternSize += counters[i]; } int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize; // If 50% of last pattern size, following last pattern, is not whitespace, fail // (but if it's whitespace to the very end of the image, that's OK) if (nextStart != end && whiteSpaceAfterEnd / 2 < lastPatternSize) { throw ReaderException.Instance; } if (usingCheckDigit) { int max = result.Length - 1; int total = 0; for (int i = 0; i < max; i++) { total += ALPHABET_STRING.IndexOf((System.Char)result[i]); } if (total % 43 != ALPHABET_STRING.IndexOf((System.Char)result[max])) { throw ReaderException.Instance; } result.Remove(max, 1); } System.String resultString = result.ToString(); if (extendedMode) { resultString = decodeExtended(resultString); } if (resultString.Length == 0) { // Almost surely a false positive throw ReaderException.Instance; } //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'" float left = (float)(start[1] + start[0]) / 2.0f; //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'" float right = (float)(nextStart + lastStart) / 2.0f; //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'" return(new Result(resultString, null, new ResultPoint[] { new ResultPoint(left, (float)rowNumber), new ResultPoint(right, (float)rowNumber) }, BarcodeFormat.CODE_39)); }
private static int[] findStartPattern(BitArray row) { int width = row.Size; int rowOffset = 0; while (rowOffset < width) { if (row.get_Renamed(rowOffset)) { break; } rowOffset++; } int counterPosition = 0; int[] counters = new int[6]; int patternStart = rowOffset; bool isWhite = false; int patternLength = counters.Length; for (int i = rowOffset; i < width; i++) { bool pixel = row.get_Renamed(i); if (pixel ^ isWhite) { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { int bestVariance = MAX_AVG_VARIANCE; int bestMatch = -1; for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) { int variance = patternMatchVariance(counters, CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE); if (variance < bestVariance) { bestVariance = variance; bestMatch = startCode; } } if (bestMatch >= 0) { // Look for whitespace before start pattern, >= 50% of width of start pattern if (row.isRange(System.Math.Max(0, patternStart - (i - patternStart) / 2), patternStart, false)) { return(new int[] { patternStart, i, bestMatch }); } } patternStart += counters[0] + counters[1]; for (int y = 2; y < patternLength; y++) { counters[y - 2] = counters[y]; } counters[patternLength - 2] = 0; counters[patternLength - 1] = 0; counterPosition--; } else { counterPosition++; } counters[counterPosition] = 1; isWhite = !isWhite; } } throw ReaderException.Instance; }
// added by .net follower (http://dotnetfollower.com) // public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) // commented by .net follower (http://dotnetfollower.com) public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Generic.Dictionary<Object, Object> hints) { int[] startPatternInfo = findStartPattern(row); int startCode = startPatternInfo[2]; int codeSet; switch (startCode) { case CODE_START_A: codeSet = CODE_CODE_A; break; case CODE_START_B: codeSet = CODE_CODE_B; break; case CODE_START_C: codeSet = CODE_CODE_C; break; default: throw ReaderException.Instance; } bool done = false; bool isNextShifted = false; System.Text.StringBuilder result = new System.Text.StringBuilder(20); int lastStart = startPatternInfo[0]; int nextStart = startPatternInfo[1]; int[] counters = new int[6]; int lastCode = 0; int code = 0; int checksumTotal = startCode; int multiplier = 0; bool lastCharacterWasPrintable = true; while (!done) { bool unshift = isNextShifted; isNextShifted = false; // Save off last code lastCode = code; // Decode another code from image code = decodeCode(row, counters, nextStart); // Remember whether the last code was printable or not (excluding CODE_STOP) if (code != CODE_STOP) { lastCharacterWasPrintable = true; } // Add to checksum computation (if not CODE_STOP of course) if (code != CODE_STOP) { multiplier++; checksumTotal += multiplier * code; } // Advance to where the next code will to start lastStart = nextStart; for (int i = 0; i < counters.Length; i++) { nextStart += counters[i]; } // Take care of illegal start codes switch (code) { case CODE_START_A: case CODE_START_B: case CODE_START_C: throw ReaderException.Instance; } switch (codeSet) { case CODE_CODE_A: if (code < 64) { result.Append((char) (' ' + code)); } else if (code < 96) { result.Append((char) (code - 64)); } else { // Don't let CODE_STOP, which always appears, affect whether whether we think the last // code was printable or not. if (code != CODE_STOP) { lastCharacterWasPrintable = false; } switch (code) { case CODE_FNC_1: case CODE_FNC_2: case CODE_FNC_3: case CODE_FNC_4_A: // do nothing? break; case CODE_SHIFT: isNextShifted = true; codeSet = CODE_CODE_B; break; case CODE_CODE_B: codeSet = CODE_CODE_B; break; case CODE_CODE_C: codeSet = CODE_CODE_C; break; case CODE_STOP: done = true; break; } } break; case CODE_CODE_B: if (code < 96) { result.Append((char) (' ' + code)); } else { if (code != CODE_STOP) { lastCharacterWasPrintable = false; } switch (code) { case CODE_FNC_1: case CODE_FNC_2: case CODE_FNC_3: case CODE_FNC_4_B: // do nothing? break; case CODE_SHIFT: isNextShifted = true; codeSet = CODE_CODE_C; break; case CODE_CODE_A: codeSet = CODE_CODE_A; break; case CODE_CODE_C: codeSet = CODE_CODE_C; break; case CODE_STOP: done = true; break; } } break; case CODE_CODE_C: if (code < 100) { if (code < 10) { result.Append('0'); } result.Append(code); } else { if (code != CODE_STOP) { lastCharacterWasPrintable = false; } switch (code) { case CODE_FNC_1: // do nothing? break; case CODE_CODE_A: codeSet = CODE_CODE_A; break; case CODE_CODE_B: codeSet = CODE_CODE_B; break; case CODE_STOP: done = true; break; } } break; } // Unshift back to another code set if we were shifted if (unshift) { switch (codeSet) { case CODE_CODE_A: codeSet = CODE_CODE_C; break; case CODE_CODE_B: codeSet = CODE_CODE_A; break; case CODE_CODE_C: codeSet = CODE_CODE_B; break; } } } // Check for ample whitespace following pattern, but, to do this we first need to remember that // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left // to read off. Would be slightly better to properly read. Here we just skip it: int width = row.Size; while (nextStart < width && row.get_Renamed(nextStart)) { nextStart++; } if (!row.isRange(nextStart, System.Math.Min(width, nextStart + (nextStart - lastStart) / 2), false)) { throw ReaderException.Instance; } // Pull out from sum the value of the penultimate check code checksumTotal -= multiplier * lastCode; // lastCode is the checksum then: if (checksumTotal % 103 != lastCode) { throw ReaderException.Instance; } // Need to pull out the check digits from string int resultLength = result.Length; // Only bother if the result had at least one character, and if the checksum digit happened to // be a printable character. If it was just interpreted as a control code, nothing to remove. if (resultLength > 0 && lastCharacterWasPrintable) { if (codeSet == CODE_CODE_C) { result.Remove(resultLength - 2, resultLength - (resultLength - 2)); } else { result.Remove(resultLength - 1, resultLength - (resultLength - 1)); } } System.String resultString = result.ToString(); if (resultString.Length == 0) { // Almost surely a false positive throw ReaderException.Instance; } //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'" float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f; //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'" float right = (float) (nextStart + lastStart) / 2.0f; //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'" return new Result(resultString, null, new ResultPoint[]{new ResultPoint(left, (float) rowNumber), new ResultPoint(right, (float) rowNumber)}, BarcodeFormat.CODE_128); }
/// <summary> Records the size of successive runs of white and black pixels in a row, starting at a given point. /// The values are recorded in the given array, and the number of runs recorded is equal to the size /// of the array. If the row starts on a white pixel at the given start point, then the first count /// recorded is the run of white pixels starting from that point; likewise it is the count of a run /// of black pixels if the row begin on a black pixels at that point. /// /// </summary> /// <param name="row">row to count from /// </param> /// <param name="start">offset into row to start at /// </param> /// <param name="counters">array into which to record counts /// </param> /// <throws> ReaderException if counters cannot be filled entirely from row before running out </throws> /// <summary> of pixels /// </summary> internal static void recordPattern(BitArray row, int start, int[] counters) { int numCounters = counters.Length; for (int i = 0; i < numCounters; i++) { counters[i] = 0; } int end = row.Size; if (start >= end) { throw ReaderException.Instance; } bool isWhite = !row.get_Renamed(start); int counterPosition = 0; int i2 = start; while (i2 < end) { bool pixel = row.get_Renamed(i2); if (pixel ^ isWhite) { // that is, exactly one is true counters[counterPosition]++; } else { counterPosition++; if (counterPosition == numCounters) { break; } else { counters[counterPosition] = 1; isWhite ^= true; // isWhite = !isWhite; } } i2++; } // If we read fully the last section of pixels and filled up our counters -- or filled // the last counter but ran off the side of the image, OK. Otherwise, a problem. if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i2 == end))) { throw ReaderException.Instance; } }
/// <param name="row">row of black/white values to search /// </param> /// <param name="rowOffset">position to start search /// </param> /// <param name="whiteFirst">if true, indicates that the pattern specifies white/black/white/... /// pixel counts, otherwise, it is interpreted as black/white/black/... /// </param> /// <param name="pattern">pattern of counts of number of black and white pixels that are being /// searched for as a pattern /// </param> /// <returns> start/end horizontal offset of guard pattern, as an array of two ints /// </returns> /// <throws> ReaderException if pattern is not found </throws> internal static int[] findGuardPattern(BitArray row, int rowOffset, bool whiteFirst, int[] pattern) { int patternLength = pattern.Length; int[] counters = new int[patternLength]; int width = row.Size; bool isWhite = false; while (rowOffset < width) { isWhite = !row.get_Renamed(rowOffset); if (whiteFirst == isWhite) { break; } rowOffset++; } int counterPosition = 0; int patternStart = rowOffset; for (int x = rowOffset; x < width; x++) { bool pixel = row.get_Renamed(x); if (pixel ^ isWhite) { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { return new int[]{patternStart, x}; } patternStart += counters[0] + counters[1]; for (int y = 2; y < patternLength; y++) { counters[y - 2] = counters[y]; } counters[patternLength - 2] = 0; counters[patternLength - 1] = 0; counterPosition--; } else { counterPosition++; } counters[counterPosition] = 1; isWhite = !isWhite; } } throw ReaderException.Instance; }
public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) { int[] start = findAsteriskPattern(row); int nextStart = start[1]; int end = row.Size; // Read off white space while (nextStart < end && !row.get_Renamed(nextStart)) { nextStart++; } System.Text.StringBuilder result = new System.Text.StringBuilder(20); int[] counters = new int[9]; char decodedChar; int lastStart; do { recordPattern(row, nextStart, counters); int pattern = toNarrowWidePattern(counters); if (pattern < 0) { throw ReaderException.Instance; } decodedChar = patternToChar(pattern); result.Append(decodedChar); lastStart = nextStart; for (int i = 0; i < counters.Length; i++) { nextStart += counters[i]; } // Read off white space while (nextStart < end && !row.get_Renamed(nextStart)) { nextStart++; } } while (decodedChar != '*'); result.Remove(result.Length - 1, 1); // remove asterisk // Look for whitespace after pattern: int lastPatternSize = 0; for (int i = 0; i < counters.Length; i++) { lastPatternSize += counters[i]; } int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize; // If 50% of last pattern size, following last pattern, is not whitespace, fail // (but if it's whitespace to the very end of the image, that's OK) if (nextStart != end && whiteSpaceAfterEnd / 2 < lastPatternSize) { throw ReaderException.Instance; } if (usingCheckDigit) { int max = result.Length - 1; int total = 0; for (int i = 0; i < max; i++) { total += ALPHABET_STRING.IndexOf((System.Char) result[i]); } if (total % 43 != ALPHABET_STRING.IndexOf((System.Char) result[max])) { throw ReaderException.Instance; } result.Remove(max, 1); } System.String resultString = result.ToString(); if (extendedMode) { resultString = decodeExtended(resultString); } if (resultString.Length == 0) { // Almost surely a false positive throw ReaderException.Instance; } //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'" float left = (float) (start[1] + start[0]) / 2.0f; //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'" float right = (float) (nextStart + lastStart) / 2.0f; //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'" return new Result(resultString, null, new ResultPoint[]{new ResultPoint(left, (float) rowNumber), new ResultPoint(right, (float) rowNumber)}, BarcodeFormat.CODE_39); }
public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) { int[] startPatternInfo = findStartPattern(row); int startCode = startPatternInfo[2]; int codeSet; switch (startCode) { case CODE_START_A: codeSet = CODE_CODE_A; break; case CODE_START_B: codeSet = CODE_CODE_B; break; case CODE_START_C: codeSet = CODE_CODE_C; break; default: throw ReaderException.Instance; } bool done = false; bool isNextShifted = false; System.Text.StringBuilder result = new System.Text.StringBuilder(20); int lastStart = startPatternInfo[0]; int nextStart = startPatternInfo[1]; int[] counters = new int[6]; int lastCode = 0; int code = 0; int checksumTotal = startCode; int multiplier = 0; bool lastCharacterWasPrintable = true; while (!done) { bool unshift = isNextShifted; isNextShifted = false; // Save off last code lastCode = code; // Decode another code from image code = decodeCode(row, counters, nextStart); // Remember whether the last code was printable or not (excluding CODE_STOP) if (code != CODE_STOP) { lastCharacterWasPrintable = true; } // Add to checksum computation (if not CODE_STOP of course) if (code != CODE_STOP) { multiplier++; checksumTotal += multiplier * code; } // Advance to where the next code will to start lastStart = nextStart; for (int i = 0; i < counters.Length; i++) { nextStart += counters[i]; } // Take care of illegal start codes switch (code) { case CODE_START_A: case CODE_START_B: case CODE_START_C: throw ReaderException.Instance; } switch (codeSet) { case CODE_CODE_A: if (code < 64) { result.Append((char)(' ' + code)); } else if (code < 96) { result.Append((char)(code - 64)); } else { // Don't let CODE_STOP, which always appears, affect whether whether we think the last // code was printable or not. if (code != CODE_STOP) { lastCharacterWasPrintable = false; } switch (code) { case CODE_FNC_1: case CODE_FNC_2: case CODE_FNC_3: case CODE_FNC_4_A: // do nothing? break; case CODE_SHIFT: isNextShifted = true; codeSet = CODE_CODE_B; break; case CODE_CODE_B: codeSet = CODE_CODE_B; break; case CODE_CODE_C: codeSet = CODE_CODE_C; break; case CODE_STOP: done = true; break; } } break; case CODE_CODE_B: if (code < 96) { result.Append((char)(' ' + code)); } else { if (code != CODE_STOP) { lastCharacterWasPrintable = false; } switch (code) { case CODE_FNC_1: case CODE_FNC_2: case CODE_FNC_3: case CODE_FNC_4_B: // do nothing? break; case CODE_SHIFT: isNextShifted = true; codeSet = CODE_CODE_C; break; case CODE_CODE_A: codeSet = CODE_CODE_A; break; case CODE_CODE_C: codeSet = CODE_CODE_C; break; case CODE_STOP: done = true; break; } } break; case CODE_CODE_C: if (code < 100) { if (code < 10) { result.Append('0'); } result.Append(code); } else { if (code != CODE_STOP) { lastCharacterWasPrintable = false; } switch (code) { case CODE_FNC_1: // do nothing? break; case CODE_CODE_A: codeSet = CODE_CODE_A; break; case CODE_CODE_B: codeSet = CODE_CODE_B; break; case CODE_STOP: done = true; break; } } break; } // Unshift back to another code set if we were shifted if (unshift) { switch (codeSet) { case CODE_CODE_A: codeSet = CODE_CODE_C; break; case CODE_CODE_B: codeSet = CODE_CODE_A; break; case CODE_CODE_C: codeSet = CODE_CODE_B; break; } } } // Check for ample whitespace following pattern, but, to do this we first need to remember that // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left // to read off. Would be slightly better to properly read. Here we just skip it: int width = row.Size; while (nextStart < width && row.get_Renamed(nextStart)) { nextStart++; } if (!row.isRange(nextStart, System.Math.Min(width, nextStart + (nextStart - lastStart) / 2), false)) { throw ReaderException.Instance; } // Pull out from sum the value of the penultimate check code checksumTotal -= multiplier * lastCode; // lastCode is the checksum then: if (checksumTotal % 103 != lastCode) { throw ReaderException.Instance; } // Need to pull out the check digits from string int resultLength = result.Length; // Only bother if the result had at least one character, and if the checksum digit happened to // be a printable character. If it was just interpreted as a control code, nothing to remove. if (resultLength > 0 && lastCharacterWasPrintable) { if (codeSet == CODE_CODE_C) { result.Remove(resultLength - 2, resultLength - (resultLength - 2)); } else { result.Remove(resultLength - 1, resultLength - (resultLength - 1)); } } System.String resultString = result.ToString(); if (resultString.Length == 0) { // Almost surely a false positive throw ReaderException.Instance; } //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'" float left = (float)(startPatternInfo[1] + startPatternInfo[0]) / 2.0f; //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'" float right = (float)(nextStart + lastStart) / 2.0f; //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'" return(new Result(resultString, null, new ResultPoint[] { new ResultPoint(left, (float)rowNumber), new ResultPoint(right, (float)rowNumber) }, BarcodeFormat.CODE_128)); }
private static int[] findAsteriskPattern(BitArray row) { int width = row.Size; int rowOffset = 0; while (rowOffset < width) { if (row.get_Renamed(rowOffset)) { break; } rowOffset++; } int counterPosition = 0; int[] counters = new int[9]; int patternStart = rowOffset; bool isWhite = false; int patternLength = counters.Length; for (int i = rowOffset; i < width; i++) { bool pixel = row.get_Renamed(i); if (pixel ^ isWhite) { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { if (toNarrowWidePattern(counters) == ASTERISK_ENCODING) { // Look for whitespace before start pattern, >= 50% of width of start pattern if (row.isRange(System.Math.Max(0, patternStart - (i - patternStart) / 2), patternStart, false)) { return new int[]{patternStart, i}; } } patternStart += counters[0] + counters[1]; for (int y = 2; y < patternLength; y++) { counters[y - 2] = counters[y]; } counters[patternLength - 2] = 0; counters[patternLength - 1] = 0; counterPosition--; } else { counterPosition++; } counters[counterPosition] = 1; isWhite = !isWhite; } } throw ReaderException.Instance; }
private static int[] findStartPattern(BitArray row) { int width = row.Size; int rowOffset = 0; while (rowOffset < width) { if (row.get_Renamed(rowOffset)) { break; } rowOffset++; } int counterPosition = 0; int[] counters = new int[6]; int patternStart = rowOffset; bool isWhite = false; int patternLength = counters.Length; for (int i = rowOffset; i < width; i++) { bool pixel = row.get_Renamed(i); if (pixel ^ isWhite) { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { int bestVariance = MAX_AVG_VARIANCE; int bestMatch = - 1; for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) { int variance = patternMatchVariance(counters, CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE); if (variance < bestVariance) { bestVariance = variance; bestMatch = startCode; } } if (bestMatch >= 0) { // Look for whitespace before start pattern, >= 50% of width of start pattern if (row.isRange(System.Math.Max(0, patternStart - (i - patternStart) / 2), patternStart, false)) { return new int[]{patternStart, i, bestMatch}; } } patternStart += counters[0] + counters[1]; for (int y = 2; y < patternLength; y++) { counters[y - 2] = counters[y]; } counters[patternLength - 2] = 0; counters[patternLength - 1] = 0; counterPosition--; } else { counterPosition++; } counters[counterPosition] = 1; isWhite = !isWhite; } } throw ReaderException.Instance; }