/// <summary> /// <p>Like <see cref="decodeRow(int,ZXing.Common.BitArray,System.Collections.Generic.IDictionary{ZXing.DecodeHintType,object})"/>, but /// allows caller to inform method about where the UPC/EAN start pattern is /// found. This allows this to be computed once and reused across many implementations.</p> /// </summary> /// <param name="rowNumber">row index into the image</param> /// <param name="row">encoding of the row of the barcode image</param> /// <param name="startGuardRange">start/end column where the opening start pattern was found</param> /// <param name="hints">optional hints that influence decoding</param> /// <returns><see cref="Result"/> encapsulating the result of decoding a barcode in the row</returns> public virtual Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange, IDictionary <DecodeHintType, object> hints) { var resultPointCallback = hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) ? null : (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; if (resultPointCallback != null) { resultPointCallback(new ResultPoint( (startGuardRange[0] + startGuardRange[1]) / 2.0f, rowNumber )); } var result = decodeRowStringBuffer; result.Length = 0; var endStart = decodeMiddle(row, startGuardRange, result); if (endStart < 0) { return(null); } if (resultPointCallback != null) { resultPointCallback(new ResultPoint( endStart, rowNumber )); } var endRange = decodeEnd(row, endStart); if (endRange == null) { return(null); } if (resultPointCallback != null) { resultPointCallback(new ResultPoint( (endRange[0] + endRange[1]) / 2.0f, rowNumber )); } // 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. var end = endRange[1]; var quietEnd = end + (end - endRange[0]); if (quietEnd >= row.Size || !row.isRange(end, quietEnd, false)) { return(null); } var resultString = result.ToString(); // UPC/EAN should never be less than 8 chars anyway if (resultString.Length < 8) { return(null); } if (!checkChecksum(resultString)) { return(null); } var left = (startGuardRange[1] + startGuardRange[0]) / 2.0f; var right = (endRange[1] + endRange[0]) / 2.0f; var format = BarcodeFormat; var decodeResult = new Result(resultString, null, // no natural byte representation for these barcodes new ResultPoint[] { new ResultPoint(left, rowNumber), new ResultPoint(right, rowNumber) }, format); var extensionResult = extensionReader.decodeRow(rowNumber, row, endRange[1]); if (extensionResult != null) { decodeResult.putMetadata(ResultMetadataType.UPC_EAN_EXTENSION, extensionResult.Text); decodeResult.putAllMetadata(extensionResult.ResultMetadata); decodeResult.addResultPoints(extensionResult.ResultPoints); int extensionLength = extensionResult.Text.Length; int[] allowedExtensions = hints != null && hints.ContainsKey(DecodeHintType.ALLOWED_EAN_EXTENSIONS) ? (int[])hints[DecodeHintType.ALLOWED_EAN_EXTENSIONS] : null; if (allowedExtensions != null) { bool valid = false; foreach (int length in allowedExtensions) { if (extensionLength == length) { valid = true; break; } } if (!valid) { return(null); } } } if (format == BarcodeFormat.EAN_13 || format == BarcodeFormat.UPC_A) { String countryID = eanManSupport.lookupCountryIdentifier(resultString); if (countryID != null) { decodeResult.putMetadata(ResultMetadataType.POSSIBLE_COUNTRY, countryID); } } return(decodeResult); }
/// <summary> /// <p>Like decodeRow(int, BitArray, java.util.Map), but /// allows caller to inform method about where the UPC/EAN start pattern is /// found. This allows this to be computed once and reused across many implementations.</p> /// </summary> virtual public Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange, IDictionary <DecodeHintType, object> hints) { ResultPointCallback resultPointCallback = hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) ? null : (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; if (resultPointCallback != null) { resultPointCallback(new ResultPoint( (startGuardRange[0] + startGuardRange[1]) / 2.0f, rowNumber )); } StringBuilder result = decodeRowStringBuffer; result.Length = 0; int endStart = decodeMiddle(row, startGuardRange, result); if (endStart < 0) { return(null); } if (resultPointCallback != null) { resultPointCallback(new ResultPoint( endStart, rowNumber )); } int[] endRange = decodeEnd(row, endStart); if (endRange == null) { return(null); } if (resultPointCallback != null) { resultPointCallback(new ResultPoint( (endRange[0] + endRange[1]) / 2.0f, rowNumber )); } // 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.Size || !row.isRange(end, quietEnd, false)) { return(null); } String resultString = result.ToString(); if (!checkChecksum(resultString)) { return(null); } float left = (startGuardRange[1] + startGuardRange[0]) / 2.0f; float right = (endRange[1] + endRange[0]) / 2.0f; BarcodeFormat format = BarcodeFormat; Result decodeResult = new Result(resultString, null, // no natural byte representation for these barcodes new ResultPoint[] { new ResultPoint(left, rowNumber), new ResultPoint(right, rowNumber) }, format); Result extensionResult = extensionReader.decodeRow(rowNumber, row, endRange[1]); if (extensionResult != null) { decodeResult.putMetadata(ResultMetadataType.UPC_EAN_EXTENSION, extensionResult.Text); decodeResult.putAllMetadata(extensionResult.ResultMetadata); decodeResult.addResultPoints(extensionResult.ResultPoints); } if (format == BarcodeFormat.EAN_13 || format == BarcodeFormat.UPC_A) { String countryID = eanManSupport.lookupCountryIdentifier(resultString); if (countryID != null) { decodeResult.putMetadata(ResultMetadataType.POSSIBLE_COUNTRY, countryID); } } return(decodeResult); }