public override Result decodeRow(int rowNumber, BitArray row, Dictionary<DecodeHintType, Object> 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++; } var result = new StringBuilder(20); var 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((Char) result[i]); } if (total%43 != ALPHABET_STRING.IndexOf((Char) result[max])) { throw ReaderException.Instance; } result.Remove(max, 1); } String resultString = result.ToString(); if (extendedMode) { resultString = decodeExtended(resultString); } if (resultString.Length == 0) { // Almost surely a false positive throw ReaderException.Instance; } float left = (start[1] + start[0])/2.0f; float right = (nextStart + lastStart)/2.0f; return new Result(resultString, null, new[] {new ResultPoint(left, rowNumber), new ResultPoint(right, rowNumber)}, BarcodeFormat.CODE_39); }
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; var 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(Math.Max(0, patternStart - (i - patternStart)/2), patternStart, false)) { return new[] {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; }
/// <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; var 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[] {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 = 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; } }