/* * Copyright 2009 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using ZXing.Common; using ZXing.Multi; using ZXing.PDF417.Internal; namespace ZXing.PDF417 { /// <summary> /// This implementation can detect and decode PDF417 codes in an image. /// /// <author>SITA Lab ([email protected])</author> /// <author>Guenther Grau</author> /// </summary> public sealed class PDF417Reader : Reader, MultipleBarcodeReader { /// <summary> /// Locates and decodes a PDF417 code in an image. /// /// <returns>a String representing the content encoded by the PDF417 code</returns> /// <exception cref="FormatException">if a PDF417 cannot be decoded</exception> /// </summary> public Result decode(BinaryBitmap image) { return decode(image, null); } /// <summary> /// Locates and decodes a barcode in some format within an image. This method also accepts /// hints, each possibly associated to some data, which may help the implementation decode. /// **Note** this will return the FIRST barcode discovered if there are many. /// </summary> /// <param name="image">image of barcode to decode</param> /// <param name="hints">passed as a <see cref="IDictionary{TKey, TValue}"/> from/// to arbitrary data. The /// meaning of the data depends upon the hint type. The implementation may or may not do /// anything with these hints.</param> /// <returns> /// String which the barcode encodes /// </returns> public Result decode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints) { Result[] results = decode(image, hints, false); if (results.Length == 0) { return null; } else { return results[0]; // First barcode discovered. } } /// <summary> /// Locates and decodes Multiple PDF417 codes in an image. /// /// <returns>an array of Strings representing the content encoded by the PDF417 codes</returns> /// </summary> public Result[] decodeMultiple(BinaryBitmap image) { return decodeMultiple(image, null); } /// <summary> /// Locates and decodes multiple barcodes in some format within an image. This method also accepts /// hints, each possibly associated to some data, which may help the implementation decode. /// </summary> /// <param name="image">image of barcode to decode</param> /// <param name="hints">passed as a <see cref="IDictionary{TKey, TValue}"/> from /// to arbitrary data. The /// meaning of the data depends upon the hint type. The implementation may or may not do /// anything with these hints.</param> /// <returns> /// String which the barcodes encode /// </returns> public Result[] decodeMultiple(BinaryBitmap image, IDictionary<DecodeHintType, object> hints) { return decode(image, hints, true); } /// <summary> /// Decode the specified image, with the hints and optionally multiple barcodes. /// Based on Owen's Comments in <see cref="ZXing.ReaderException"/>, this method has been modified to continue silently /// if a barcode was not decoded where it was detected instead of throwing a new exception object. /// </summary> /// <param name="image">Image.</param> /// <param name="hints">Hints.</param> /// <param name="multiple">If set to <c>true multiple. private static Result[] decode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints, bool multiple) { var results = new List<Result>(); var detectorResult = Detector.detect(image, hints, multiple); if (detectorResult != null) { foreach (var points in detectorResult.Points) { var decoderResult = PDF417ScanningDecoder.decode(detectorResult.Bits, points[4], points[5], points[6], points[7], getMinCodewordWidth(points), getMaxCodewordWidth(points)); if (decoderResult == null) { continue; } var result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.PDF_417); result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.ECLevel); var pdf417ResultMetadata = (PDF417ResultMetadata) decoderResult.Other; if (pdf417ResultMetadata != null) { result.putMetadata(ResultMetadataType.PDF417_EXTRA_METADATA, pdf417ResultMetadata); } results.Add(result); } } return results.ToArray(); } /// <summary> /// Gets the maximum width of the barcode /// </summary> /// <returns>The max width.</returns> /// <param name="p1">P1.</param> /// <param name="p2">P2.</param> private static int getMaxWidth(ResultPoint p1, ResultPoint p2) { if (p1 == null || p2 == null) { return 0; } return (int) Math.Abs(p1.X - p2.X); } /// <summary> /// Gets the minimum width of the barcode /// </summary> /// <returns>The minimum width.</returns> /// <param name="p1">P1.</param> /// <param name="p2">P2.</param> private static int getMinWidth(ResultPoint p1, ResultPoint p2) { if (p1 == null || p2 == null) { return int.MaxValue; } return (int) Math.Abs(p1.X - p2.X); } /// <summary> /// Gets the maximum width of the codeword. /// </summary> /// <returns>The max codeword width.</returns> /// <param name="p">P.</param> private static int getMaxCodewordWidth(ResultPoint[] p) { return Math.Max( Math.Max(getMaxWidth(p[0], p[4]), getMaxWidth(p[6], p[2])*PDF417Common.MODULES_IN_CODEWORD/ PDF417Common.MODULES_IN_STOP_PATTERN), Math.Max(getMaxWidth(p[1], p[5]), getMaxWidth(p[7], p[3])*PDF417Common.MODULES_IN_CODEWORD/ PDF417Common.MODULES_IN_STOP_PATTERN)); } /// <summary> /// Gets the minimum width of the codeword. /// </summary> /// <returns>The minimum codeword width.</returns> /// <param name="p">P.</param> private static int getMinCodewordWidth(ResultPoint[] p) { return Math.Min( Math.Min(getMinWidth(p[0], p[4]), getMinWidth(p[6], p[2])*PDF417Common.MODULES_IN_CODEWORD/ PDF417Common.MODULES_IN_STOP_PATTERN), Math.Min(getMinWidth(p[1], p[5]), getMinWidth(p[7], p[3])*PDF417Common.MODULES_IN_CODEWORD/ PDF417Common.MODULES_IN_STOP_PATTERN)); } /// <summary> /// Resets any internal state the implementation has after a decode, to prepare it /// for reuse. /// </summary> public void reset() { // do nothing } } }