public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) { StringBuilder result = new StringBuilder(20); // Find out where the Middle section (payload) starts & ends int[] startRange = decodeStart(row); int[] endRange = decodeEnd(row); decodeMiddle(row, startRange[1], endRange[0], result); string resultString = result.ToString(); // To avoid false positives with 2D barcodes (and other patterns), make // an assumption that the decoded string must be 6, 10 or 14 digits. int length = resultString.Length; if (length != 6 && length != 10 && length != 14) { throw new ReaderException(); } return new Result( resultString, null, // no natural byte representation for these barcodes new ResultPoint[] { new GenericResultPoint(startRange[1], (float) rowNumber), new GenericResultPoint(startRange[0], (float) rowNumber)}, BarcodeFormat.ITF); }
public BitArray getBlackRow(int y, BitArray row, int startX, int getWidth) { if (row == null || row.getSize() < getWidth) { row = new BitArray(getWidth); } else { row.clear(); } // Reuse the same int array each time initLuminances(); luminances = getLuminanceRow(y, luminances); // If the current decoder calculated the blackPoint based on one row, assume we're trying to // decode a 1D barcode, and apply some sharpening. if (lastMethod.Equals(BlackPointEstimationMethod.ROW_SAMPLING)) { int left = luminances[startX]; int center = luminances[startX + 1]; for (int x = 1; x < getWidth - 1; x++) { int right = luminances[startX + x + 1]; // Simple -1 4 -1 box filter with a weight of 2 int luminance = ((center << 2) - left - right) >> 1; if (luminance < blackPoint) { row.set(x); } left = center; center = right; } } else { for (int x = 0; x < getWidth; x++) { if (luminances[startX + x] < blackPoint) { row.set(x); } } } return row; }
protected override int decodeMiddle(BitArray row, int[] startRange, StringBuilder result) { int[] counters = decodeMiddleCounters; counters[0] = 0; counters[1] = 0; counters[2] = 0; counters[3] = 0; int end = row.getSize(); int rowOffset = startRange[1]; for (int x = 0; x < 4 && rowOffset < end; x++) { int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS); result.Append((char) ('0' + bestMatch)); for (int i = 0; i < counters.Length; i++) { rowOffset += counters[i]; } } int[] middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN); rowOffset = middleRange[1]; for (int x = 0; x < 4 && rowOffset < end; x++) { int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS); result.Append((char) ('0' + bestMatch)); for (int i = 0; i < counters.Length; i++) { rowOffset += counters[i]; } } return rowOffset; }
public BitArray getBlackColumn(int x, BitArray column, int startY, int getHeight) { if (column == null || column.getSize() < getHeight) { column = new BitArray(getHeight); } else { column.clear(); } // Reuse the same int array each time initLuminances(); luminances = getLuminanceColumn(x, luminances); // We don't handle "row sampling" specially here for (int y = 0; y < getHeight; y++) { if (luminances[startY + y] < blackPoint) { column.set(y); } } return(column); }
public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) { // Compute this location once and reuse it on multiple implementations int[] startGuardPattern = AbstractUPCEANReader.findStartGuardPattern(row); int size = readers.Count; for (int i = 0; i < size; i++) { UPCEANReader reader = (UPCEANReader) readers[i]; Result result; try { result = reader.decodeRow(rowNumber, row, startGuardPattern); } catch (ReaderException re) { continue; } // Special case: a 12-digit code encoded in UPC-A is identical to a "0" // followed by those 12 digits encoded as EAN-13. Each will recognize such a code, // UPC-A as a 12-digit string and EAN-13 as a 13-digit string starting with "0". // Individually these are correct and their readers will both read such a code // and correctly call it EAN-13, or UPC-A, respectively. // // In this case, if we've been looking for both types, we'd like to call it // a UPC-A code. But for efficiency we only run the EAN-13 decoder to also read // UPC-A. So we special case it here, and convert an EAN-13 result to a UPC-A // result if appropriate. if (result.getBarcodeFormat().Equals(BarcodeFormat.EAN_13) && result.getText()[0] == '0') { return new Result(result.getText().Substring(1), null, result.getResultPoints(), BarcodeFormat.UPC_A); } return result; } throw new ReaderException(); }
public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) { int size = readers.Count; for (int i = 0; i < size; i++) { OneDReader reader = (OneDReader) readers[i]; try { return reader.decodeRow(rowNumber, row, hints); } catch (ReaderException re) { // continue } } throw new ReaderException(); }
public BitArray getBlackRow(int y, BitArray row, int startX, int getWidth) { if (row == null || row.getSize() < getWidth) { row = new BitArray(getWidth); } else { row.clear(); } // Reuse the same int array each time initLuminances(); luminances = getLuminanceRow(y, luminances); // If the current decoder calculated the blackPoint based on one row, assume we're trying to // decode a 1D barcode, and apply some sharpening. if (lastMethod.Equals(BlackPointEstimationMethod.ROW_SAMPLING)) { int left = luminances[startX]; int center = luminances[startX + 1]; for (int x = 1; x < getWidth - 1; x++) { int right = luminances[startX + x + 1]; // Simple -1 4 -1 box filter with a weight of 2 int luminance = ((center << 2) - left - right) >> 1; if (luminance < blackPoint) { row.set(x); } left = center; center = right; } } else { for (int x = 0; x < getWidth; x++) { if (luminances[startX + x] < blackPoint) { row.set(x); } } } return(row); }
protected override int decodeMiddle(BitArray row, int[] startRange, StringBuilder resultString) { int[] counters = decodeMiddleCounters; counters[0] = 0; counters[1] = 0; counters[2] = 0; counters[3] = 0; int end = row.getSize(); int rowOffset = startRange[1]; int lgPatternFound = 0; for (int x = 0; x < 6 && rowOffset < end; x++) { int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS); resultString.Append((char) ('0' + bestMatch % 10)); for (int i = 0; i < counters.Length; i++) { rowOffset += counters[i]; } if (bestMatch >= 10) { lgPatternFound |= 1 << (5 - x); } } determineFirstDigit(resultString, lgPatternFound); int[] middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN); rowOffset = middleRange[1]; for (int x = 0; x < 6 && rowOffset < end; x++) { int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS); resultString.Append((char) ('0' + bestMatch)); for (int i = 0; i < counters.Length; i++) { rowOffset += counters[i]; } } return rowOffset; }
/** * Attempts to decode a single UPC/EAN-encoded digit. * * @param row row of black/white values to decode * @param counters the counts of runs of observed black/white/black/... values * @param rowOffset horizontal offset to start decoding from * @param patterns the set of patterns to use to decode -- sometimes different encodings * for the digits 0-9 are used, and this indicates the encodings for 0 to 9 that should * be used * @return horizontal offset of first pixel beyond the decoded digit * @throws ReaderException if digit cannot be decoded */ public static int decodeDigit(BitArray row, int[] counters, int rowOffset, int[][] patterns) { recordPattern(row, rowOffset, counters); int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept int bestMatch = -1; int max = patterns.Length; for (int i = 0; i < max; i++) { int[] pattern = patterns[i]; int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE); if (variance < bestVariance) { bestVariance = variance; bestMatch = i; } } if (bestMatch >= 0) { return bestMatch; } else { throw new ReaderException(); } }
private void Worker() { float fY1; float fY2; float scale; // calculate picFrame just once if (picFrame == RectangleF.Empty) { // check if device has retina display, if so scale factor by 2 if (UIScreen.MainScreen.RespondsToSelector(new MonoTouch.ObjCRuntime.Selector(@"scale")) && UIScreen.MainScreen.Scale == 2) scale = 2f; else scale = 1f; // check if the device is an ipad or an iphone if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone) { fY1 = 146f / UIScreen.MainScreen.Bounds.Height * scale; fY2 = 157f / UIScreen.MainScreen.Bounds.Height * scale; } else { // ipad - constants probably need to be modified if running at native screen res fY1 = 146f / UIScreen.MainScreen.Bounds.Height * scale; fY2 = 157f / UIScreen.MainScreen.Bounds.Height * scale; } picFrame = new RectangleF(0, UIScreen.MainScreen.Bounds.Height * fY1, UIScreen.MainScreen.Bounds.Width * scale, UIScreen.MainScreen.Bounds.Height * fY2); } if(hints==null) { var list = new ArrayList(); list.Add(com.google.zxing.BarcodeFormat.EAN_8); list.Add(com.google.zxing.BarcodeFormat.EAN_13); hints = new Hashtable(); hints.Add(com.google.zxing.DecodeHintType.POSSIBLE_FORMATS, list); hints.Add(com.google.zxing.DecodeHintType.NEED_RESULT_POINT_CALLBACK, new ResultCallBack(this)); } if(_multiFormatOneDReader == null) { _multiFormatOneDReader = new com.google.zxing.oned.MultiFormatOneDReader(hints); } // Capturing screen image using (var screenImage = CGImage.ScreenImage.WithImageInRect(picFrame)) { _theScreenImage = UIImage.FromImage(screenImage); Bitmap srcbitmap = new System.Drawing.Bitmap(_theScreenImage); LuminanceSource source = null; BinaryBitmap bitmap = null; try { source = new RGBLuminanceSource(srcbitmap, screenImage.Width, screenImage.Height); bitmap = new BinaryBitmap(new HybridBinarizer(source)); com.google.zxing.common.BitArray row = new com.google.zxing.common.BitArray(screenImage.Width); int middle = screenImage.Height >> 1; int rowStep = System.Math.Max(1, screenImage.Height >> (4)); for (int x = 0; x < 9; x++) { // Scanning from the middle out. Determine which row we're looking at next: int rowStepsAboveOrBelow = (x + 1) >> 1; bool isAbove = (x & 0x01) == 0; // i.e. is x even? int rowNumber = middle + rowStep * (isAbove?rowStepsAboveOrBelow:- rowStepsAboveOrBelow); if (rowNumber < 0 || rowNumber >= screenImage.Height) { // Oops, if we run off the top or bottom, stop break; } // Estimate black point for this row and load it: try { row = bitmap.getBlackRow(rowNumber, row); var resultb = _multiFormatOneDReader.decodeRow(rowNumber, row, hints); if(resultb.Text!=null) { BeepOrVibrate(); _parentViewController.BarCodeScanned(resultb); break; } else { continue; } } catch (ReaderException re) { continue; } } // var result = _barcodeReader.decodeWithState(bitmap); // // if(result.Text!=null) // { // _multiFormatOneDReader = null; // BeepOrVibrate(); // _parentViewController.BarCodeScanned(result); // } } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { if(bitmap!=null) bitmap = null; if(source!=null) source = null; if(srcbitmap!=null) srcbitmap = null; } } }
int[] decodeEnd(BitArray row, int endStart) { return findGuardPattern(row, endStart, false, START_END_PATTERN); }
/// <summary> A fast method to retrieve one row of data from the matrix as a BitArray. /// /// </summary> /// <param name="y">The row to retrieve /// </param> /// <param name="row">An optional caller-allocated BitArray, will be allocated if null or too small /// </param> /// <returns> The resulting BitArray - this reference should always be used even when passing /// your own row /// </returns> public BitArray getRow(int y, BitArray row) { if (row == null || row.Size < width) { row = new BitArray(width); } int offset = y * rowSize; for (int x = 0; x < rowSize; x++) { row.setBulk(x << 5, bits[offset + x]); } return row; }
private void Worker() { //iphone 4 : 960 x 640 //iphone 3 : 320 x 480 if(DeviceHardware.Version == DeviceHardware.HardwareVersion.iPhone4) { picFrame = new RectangleF(0, 146*2, 320*2, 157*2); } if(hints==null) { var list = new ArrayList(); list.Add(com.google.zxing.BarcodeFormat.EAN_8); list.Add(com.google.zxing.BarcodeFormat.EAN_13); hints = new Hashtable(); hints.Add(com.google.zxing.DecodeHintType.POSSIBLE_FORMATS, list); hints.Add(com.google.zxing.DecodeHintType.NEED_RESULT_POINT_CALLBACK, new ResultCallBack(this)); } if(_multiFormatOneDReader == null) { _multiFormatOneDReader = new com.google.zxing.oned.MultiFormatOneDReader(hints); } // Capturing screen image using (var screenImage = CGImage.ScreenImage.WithImageInRect(picFrame)) { _theScreenImage = UIImage.FromImage(screenImage); Bitmap srcbitmap = new System.Drawing.Bitmap(_theScreenImage); LuminanceSource source = null; BinaryBitmap bitmap = null; try { source = new RGBLuminanceSource(srcbitmap, screenImage.Width, screenImage.Height); bitmap = new BinaryBitmap(new HybridBinarizer(source)); com.google.zxing.common.BitArray row = new com.google.zxing.common.BitArray(screenImage.Width); int middle = screenImage.Height >> 1; int rowStep = System.Math.Max(1, screenImage.Height >> (4)); for (int x = 0; x < 9; x++) { // Scanning from the middle out. Determine which row we're looking at next: int rowStepsAboveOrBelow = (x + 1) >> 1; bool isAbove = (x & 0x01) == 0; // i.e. is x even? int rowNumber = middle + rowStep * (isAbove?rowStepsAboveOrBelow:- rowStepsAboveOrBelow); if (rowNumber < 0 || rowNumber >= screenImage.Height) { // Oops, if we run off the top or bottom, stop break; } // Estimate black point for this row and load it: try { row = bitmap.getBlackRow(rowNumber, row); var resultb = _multiFormatOneDReader.decodeRow(rowNumber, row, hints); if(resultb.Text!=null) { BeepOrVibrate(); _parentViewController.BarCodeScanned(resultb); break; } else { continue; } } catch (ReaderException re) { continue; } } // var result = _barcodeReader.decodeWithState(bitmap); // // if(result.Text!=null) // { // _multiFormatOneDReader = null; // BeepOrVibrate(); // _parentViewController.BarCodeScanned(result); // } } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { if(bitmap!=null) bitmap = null; if(source!=null) source = null; if(srcbitmap!=null) srcbitmap = null; } } }
/** * Subclasses override this to decode the portion of a barcode between the start and end guard patterns. * * @param row row of black/white values to search * @param startRange start/end offset of start guard pattern * @param resultString {@link StringBuffer} to append decoded chars to * @return horizontal offset of first pixel after the "middle" that was decoded * @throws ReaderException if decoding could not complete successfully */ protected abstract int decodeMiddle(BitArray row, int[] startRange, StringBuilder resultString);
/** * @param row row of black/white values to search * @param rowOffset position to start search * @param pattern pattern of counts of number of black and white pixels that are * being searched for as a pattern * @return start/end horizontal offset of guard pattern, as an array of two * ints * @throws ReaderException if pattern is not found */ int[] findGuardPattern(BitArray row, int rowOffset, int[] pattern) { // TODO: This is very similar to implementation in AbstractUPCEANReader. Consider if they can be merged to // a single method. int patternLength = pattern.Length; int[] counters = new int[patternLength]; int width = row.getSize(); bool isWhite = false; int counterPosition = 0; int patternStart = rowOffset; for (int x = rowOffset; x < width; x++) { bool pixel = row.get(x); if ((!pixel && isWhite) || (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 new ReaderException(); }
/** * 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 * * @param row bit array representing the scanned barcode. * @param startPattern index into row of the start or end pattern. * @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown. */ 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(i)) { break; } quietCount--; } if (quietCount != 0) { // Unable to find the necessary number of quiet zone pixels. throw new ReaderException(); } }
private void Worker() { //iphone 4 : 960 x 640 //iphone 3 : 320 x 480 if (DeviceHardware.Version == DeviceHardware.HardwareVersion.iPhone4) { picFrame = new RectangleF(0, 146 * 2, 320 * 2, 157 * 2); } if (hints == null) { var list = new ArrayList(); list.Add(com.google.zxing.BarcodeFormat.EAN_8); list.Add(com.google.zxing.BarcodeFormat.EAN_13); hints = new Hashtable(); hints.Add(com.google.zxing.DecodeHintType.POSSIBLE_FORMATS, list); hints.Add(com.google.zxing.DecodeHintType.NEED_RESULT_POINT_CALLBACK, new ResultCallBack(this)); } if (_multiFormatOneDReader == null) { _multiFormatOneDReader = new com.google.zxing.oned.MultiFormatOneDReader(hints); } // Capturing screen image using (var screenImage = CGImage.ScreenImage.WithImageInRect(picFrame)) { _theScreenImage = UIImage.FromImage(screenImage); Bitmap srcbitmap = new System.Drawing.Bitmap(_theScreenImage); LuminanceSource source = null; BinaryBitmap bitmap = null; try { source = new RGBLuminanceSource(srcbitmap, screenImage.Width, screenImage.Height); bitmap = new BinaryBitmap(new HybridBinarizer(source)); com.google.zxing.common.BitArray row = new com.google.zxing.common.BitArray(screenImage.Width); int middle = screenImage.Height >> 1; int rowStep = System.Math.Max(1, screenImage.Height >> (4)); for (int x = 0; x < 9; x++) { // Scanning from the middle out. Determine which row we're looking at next: int rowStepsAboveOrBelow = (x + 1) >> 1; bool isAbove = (x & 0x01) == 0; // i.e. is x even? int rowNumber = middle + rowStep * (isAbove?rowStepsAboveOrBelow:-rowStepsAboveOrBelow); if (rowNumber < 0 || rowNumber >= screenImage.Height) { // Oops, if we run off the top or bottom, stop break; } // Estimate black point for this row and load it: try { row = bitmap.getBlackRow(rowNumber, row); var resultb = _multiFormatOneDReader.decodeRow(rowNumber, row, hints); if (resultb.Text != null) { BeepOrVibrate(); _parentViewController.BarCodeScanned(resultb); break; } else { continue; } } catch (ReaderException re) { continue; } } // var result = _barcodeReader.decodeWithState(bitmap); // // if(result.Text!=null) // { // _multiFormatOneDReader = null; // BeepOrVibrate(); // _parentViewController.BarCodeScanned(result); // } } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { if (bitmap != null) { bitmap = null; } if (source != null) { source = null; } if (srcbitmap != null) { srcbitmap = null; } } } }
/** * Identify where the end of the middle / payload section ends. * * @param row row of black/white values to search * @return Array, containing index of start of 'end block' and end of 'end * block' * @throws ReaderException */ int[] decodeEnd(BitArray row) { // For convenience, reverse the row and then // search from 'the start' for the end block row.reverse(); int endStart = skipWhiteSpace(row); int[] endPattern; try { endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED); } catch (ReaderException e) { // Put our row of data back the right way before throwing row.reverse(); throw e; } // 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. // ref: http://www.barcode-1.net/i25code.html validateQuietZone(row, endPattern[0]); // Now recalc the indicies of where the 'endblock' starts & stops to // accomodate // the reversed nature of the search int temp = endPattern[0]; endPattern[0] = row.getSize() - endPattern[1]; endPattern[1] = row.getSize() - temp; // Put the row back the righ way. row.reverse(); return endPattern; }
/** * <p>This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since * it's pretty performance-critical and so is written to be fast foremost.</p> * * @return {@link AlignmentPattern} if found * @throws ReaderException if not found */ public AlignmentPattern find() { int startX = this.startX; int height = this.height; int maxJ = startX + width; int middleI = startY + (height >> 1); BitArray luminanceRow = new BitArray(width); // We are looking for black/white/black modules in 1:1:1 ratio; // this tracks the number of black/white/black modules seen so far int[] stateCount = new int[3]; for (int iGen = 0; iGen < height; iGen++) { // Search from middle outwards int i = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1)); image.getBlackRow(i, luminanceRow, startX, width); stateCount[0] = 0; stateCount[1] = 0; stateCount[2] = 0; int j = startX; // Burn off leading white pixels before anything else; if we start in the middle of // a white run, it doesn't make sense to count its length, since we don't know if the // white run continued to the left of the start point while (j < maxJ && !luminanceRow.get(j - startX)) { j++; } int currentState = 0; while (j < maxJ) { if (luminanceRow.get(j - startX)) { // Black pixel if (currentState == 1) { // Counting black pixels stateCount[currentState]++; } else { // Counting white pixels if (currentState == 2) { // A winner? if (foundPatternCross(stateCount)) { // Yes AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, j); if (confirmed != null) { return confirmed; } } stateCount[0] = stateCount[2]; stateCount[1] = 1; stateCount[2] = 0; currentState = 1; } else { stateCount[++currentState]++; } } } else { // White pixel if (currentState == 1) { // Counting black pixels currentState++; } stateCount[currentState]++; } j++; } if (foundPatternCross(stateCount)) { AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, maxJ); if (confirmed != null) { return confirmed; } } } // Hmm, nothing we saw was observed and confirmed twice. If we had // any guess at all, return it. if (!(possibleCenters.Count==0)) { return (AlignmentPattern) possibleCenters[0]; } throw new ReaderException(); }
public Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange) { return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange)); }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: private static int[] findAsteriskPattern(com.google.zxing.common.BitArray row, int[] counters) throws com.google.zxing.NotFoundException private static int[] findAsteriskPattern(BitArray row, int[] counters) { int width = row.Size; int rowOffset = row.getNextSet(0); int counterPosition = 0; int patternStart = rowOffset; bool isWhite = false; int patternLength = counters.Length; for (int i = rowOffset; i < width; i++) { if (row.get(i) ^ isWhite) { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { // Look for whitespace before start pattern, >= 50% of width of start pattern if (toNarrowWidePattern(counters) == ASTERISK_ENCODING && row.isRange(Math.Max(0, patternStart - ((i - patternStart) >> 1)), patternStart, false)) { return new int[]{patternStart, i}; } patternStart += counters[0] + counters[1]; Array.Copy(counters, 2, counters, 0, patternLength - 2); counters[patternLength - 2] = 0; counters[patternLength - 1] = 0; counterPosition--; } else { counterPosition++; } counters[counterPosition] = 1; isWhite = !isWhite; } } throw NotFoundException.NotFoundInstance; }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public com.google.zxing.Result decodeRow(int rowNumber, com.google.zxing.common.BitArray row, java.util.Map<com.google.zxing.DecodeHintType,?> hints) throws com.google.zxing.NotFoundException, com.google.zxing.ChecksumException, com.google.zxing.FormatException public override Result decodeRow(int rowNumber, BitArray row, IDictionary<DecodeHintType, object> hints) { int[] theCounters = counters; theCounters.Fill(0); StringBuilder result = decodeRowResult; result.Length = 0; int[] start = findAsteriskPattern(row, theCounters); // Read off white space int nextStart = row.getNextSet(start[1]); int end = row.Size; char decodedChar; int lastStart; do { recordPattern(row, nextStart, theCounters); int pattern = toNarrowWidePattern(theCounters); if (pattern < 0) { throw NotFoundException.NotFoundInstance; } decodedChar = patternToChar(pattern); result.Append(decodedChar); lastStart = nextStart; foreach (int counter in theCounters) { nextStart += counter; } // Read off white space nextStart = row.getNextSet(nextStart); } while (decodedChar != '*'); result.Length = result.Length - 1; // remove asterisk // Look for whitespace after pattern: int lastPatternSize = 0; foreach (int counter in theCounters) { lastPatternSize += counter; } 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 >> 1) < lastPatternSize) { throw NotFoundException.NotFoundInstance; } if (usingCheckDigit) { int max = result.Length - 1; int total = 0; for (int i = 0; i < max; i++) { total += ALPHABET_STRING.IndexOf(decodeRowResult[i]); } if (result[max] != ALPHABET[total % 43]) { throw ChecksumException.ChecksumInstance; } result.Length = max; } if (result.Length == 0) { // false positive throw NotFoundException.NotFoundInstance; } string resultString; if (extendedMode) { resultString = decodeExtended(result.ToString()); } else { resultString = result.ToString(); } float left = (float)(start[1] + start[0]) / 2.0f; float right = (float)(nextStart + lastStart) / 2.0f; return new Result(resultString, null, new ResultPoint[]{new ResultPoint(left, (float) rowNumber), new ResultPoint(right, (float) rowNumber)}, BarcodeFormat.CODE_39); }
public Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) { return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, hints)); }
/** * @param row row of black/white values to search * @param payloadStart offset of start pattern * @param resultString {@link StringBuilder} to Append decoded chars to * @throws ReaderException if decoding could not complete successfully */ static void decodeMiddle(BitArray row, int payloadStart, int payloadEnd, StringBuilder resultString) { // Digits are interleaved in pairs - 5 black lines for one digit, and the // 5 // interleaved white lines for the second digit. // Therefore, need to scan 10 lines and then // split these into two arrays int[] counterDigitPair = new int[10]; int[] counterBlack = new int[5]; int[] counterWhite = new int[5]; while (payloadStart < payloadEnd) { // Get 10 runs of black/white. recordPattern(row, payloadStart, counterDigitPair); // Split them into each array for (int k = 0; k < 5; k++) { int twoK = k << 1; counterBlack[k] = counterDigitPair[twoK]; counterWhite[k] = counterDigitPair[twoK + 1]; } int bestMatch = decodeDigit(counterBlack); resultString.Append((char) ('0' + bestMatch)); bestMatch = decodeDigit(counterWhite); resultString.Append((char) ('0' + bestMatch)); for (int i = 0; i < counterDigitPair.Length; i++) { payloadStart += counterDigitPair[i]; } } }
/** * @param row row of black/white values to search * @param rowOffset position to start search * @param whiteFirst if true, indicates that the pattern specifies white/black/white/... * pixel counts, otherwise, it is interpreted as black/white/black/... * @param pattern pattern of counts of number of black and white pixels that are being * searched for as a pattern * @return start/end horizontal offset of guard pattern, as an array of two ints * @throws ReaderException if pattern is not found */ public static int[] findGuardPattern(BitArray row, int rowOffset, bool whiteFirst, int[] pattern) { int patternLength = pattern.Length; int[] counters = new int[patternLength]; int width = row.getSize(); bool isWhite = false; while (rowOffset < width) { isWhite = !row.get(rowOffset); if (whiteFirst == isWhite) { break; } rowOffset++; } int counterPosition = 0; int patternStart = rowOffset; for (int x = rowOffset; x < width; x++) { bool pixel = row.get(x); if ((!pixel && isWhite) || (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 new ReaderException(); }
/** * Identify where the start of the middle / payload section starts. * * @param row row of black/white values to search * @return Array, containing index of start of 'start block' and end of * 'start block' * @throws ReaderException */ int[] decodeStart(BitArray row) { int endStart = skipWhiteSpace(row); int[] startPattern = findGuardPattern(row, endStart, START_PATTERN); // Determine the width of a narrow line in pixels. We can do this by // getting the width of the start pattern and dividing by 4 because its // made up of 4 narrow lines. this.narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; validateQuietZone(row, startPattern[0]); return startPattern; }
public static int[] findStartGuardPattern(BitArray row) { bool foundStart = false; int[] startRange = null; int nextStart = 0; while (!foundStart) { startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN); int start = startRange[0]; nextStart = startRange[1]; // Make sure there is a quiet zone at least as big as the start pattern before the barcode. If // this check would run off the left edge of the image, do not accept this barcode, as it is // very likely to be a false positive. int quietStart = start - (nextStart - start); if (quietStart >= 0) { foundStart = row.isRange(quietStart, start, false); } } return startRange; }
/** * Skip all whitespace until we get to the first black line. * * @param row row of black/white values to search * @return index of the first black line. * @throws ReaderException Throws exception if no black lines are found in the row */ private int skipWhiteSpace(BitArray row) { int width = row.getSize(); int endStart = 0; while (endStart < width) { if (row.get(endStart)) { break; } endStart++; } if (endStart == width) { throw new ReaderException(); } return endStart; }
public int[] decodeEnd(BitArray row, int endStart) { return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN); }
public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) { return decodeRow(rowNumber, row, findStartGuardPattern(row)); }
// Applies simple sharpening to the row data to improve performance of the 1D Readers. public override BitArray getBlackRow(int y, BitArray row) { LuminanceSource source = LuminanceSource; int width = source.Width; if (row == null || row.Size < width) { row = new BitArray(width); } else { row.clear(); } initArrays(width); sbyte[] localLuminances = source.getRow(y, luminances); int[] localBuckets = buckets; for (int x = 0; x < width; x++) { int pixel = localLuminances[x] & 0xff; localBuckets[pixel >> LUMINANCE_SHIFT]++; } int blackPoint = estimateBlackPoint(localBuckets); int left = localLuminances[0] & 0xff; int center = localLuminances[1] & 0xff; for (int x = 1; x < width - 1; x++) { int right = localLuminances[x + 1] & 0xff; // A simple -1 4 -1 box filter with a weight of 2. int luminance = ((center << 2) - left - right) >> 1; if (luminance < blackPoint) { row.set_Renamed(x); } left = center; center = right; } return row; }
public FinderPatternInfo find(System.Collections.Hashtable hints) { bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); int maxI = image.getHeight(); int maxJ = image.getWidth(); // We are looking for black/white/black/white/black modules in // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the // image, and then account for the center being 3 modules in size. This gives the smallest // number of pixels the center could be, so skip this often. When trying harder, look for all // QR versions regardless of how dense they are. int iSkip = (int) (maxI / (MAX_MODULES * 4.0f) * 3); if (iSkip < MIN_SKIP || tryHarder) { iSkip = MIN_SKIP; } bool done = false; int[] stateCount = new int[5]; BitArray blackRow = new BitArray(maxJ); for (int i = iSkip - 1; i < maxI && !done; i += iSkip) { // Get a row of black/white values blackRow = image.getBlackRow(i, blackRow, 0, maxJ); stateCount[0] = 0; stateCount[1] = 0; stateCount[2] = 0; stateCount[3] = 0; stateCount[4] = 0; int currentState = 0; for (int j = 0; j < maxJ; j++) { if (blackRow.get(j)) { // Black pixel if ((currentState & 1) == 1) { // Counting white pixels currentState++; } stateCount[currentState]++; } else { // White pixel if ((currentState & 1) == 0) { // Counting black pixels if (currentState == 4) { // A winner? if (foundPatternCross(stateCount)) { // Yes bool confirmed = handlePossibleCenter(stateCount, i, j); if (confirmed) { // Start examining every other line. Checking each line turned out to be too // expensive and didn't improve performance. iSkip = 2; if (hasSkipped) { done = haveMulitplyConfirmedCenters(); } else { int rowSkip = findRowSkip(); if (rowSkip > stateCount[2]) { // Skip rows between row of lower confirmed center // and top of presumed third confirmed center // but back up a bit to get a full chance of detecting // it, entire width of center of finder pattern // Skip by rowSkip, but back off by stateCount[2] (size of last center // of pattern we saw) to be conservative, and also back off by iSkip which // is about to be re-added i += rowSkip - stateCount[2] - iSkip; j = maxJ - 1; } } } else { // Advance to next black pixel do { j++; } while (j < maxJ && !blackRow.get(j)); j--; // back up to that last white pixel } // Clear state to start looking again currentState = 0; stateCount[0] = 0; stateCount[1] = 0; stateCount[2] = 0; stateCount[3] = 0; stateCount[4] = 0; } else { // No, shift counts back by two stateCount[0] = stateCount[2]; stateCount[1] = stateCount[3]; stateCount[2] = stateCount[4]; stateCount[3] = 1; stateCount[4] = 0; currentState = 3; } } else { stateCount[++currentState]++; } } else { // Counting white pixels stateCount[currentState]++; } } } if (foundPatternCross(stateCount)) { bool confirmed = handlePossibleCenter(stateCount, i, maxJ); if (confirmed) { iSkip = stateCount[0]; if (hasSkipped) { // Found a third one done = haveMulitplyConfirmedCenters(); } } } } FinderPattern[] patternInfo = selectBestPatterns(); GenericResultPoint.orderBestPatterns(patternInfo); return new FinderPatternInfo(patternInfo); }
public Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange) { StringBuilder result = decodeRowStringBuffer; result.Length = 0; int endStart = decodeMiddle(row, startGuardRange, result); int[] endRange = decodeEnd(row, endStart); // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The // spec might want more whitespace, but in practice this is the maximum we can count on. int end = endRange[1]; int quietEnd = end + (end - endRange[0]); if (quietEnd >= row.getSize() || !row.isRange(end, quietEnd, false)) { throw new ReaderException(); } String resultString = result.ToString(); if (!checkChecksum(resultString)) { throw new ReaderException(); } float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f; float right = (float) (endRange[1] + endRange[0]) / 2.0f; return new Result(resultString, null, // no natural byte representation for these barcodes new ResultPoint[]{ new GenericResultPoint(left, (float) rowNumber), new GenericResultPoint(right, (float) rowNumber)}, getBarcodeFormat()); }