• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.zxing.pdf417;
18 
19 import com.google.zxing.BarcodeFormat;
20 import com.google.zxing.BinaryBitmap;
21 import com.google.zxing.ChecksumException;
22 import com.google.zxing.DecodeHintType;
23 import com.google.zxing.FormatException;
24 import com.google.zxing.NotFoundException;
25 import com.google.zxing.Reader;
26 import com.google.zxing.Result;
27 import com.google.zxing.ResultMetadataType;
28 import com.google.zxing.ResultPoint;
29 import com.google.zxing.common.DecoderResult;
30 import com.google.zxing.multi.MultipleBarcodeReader;
31 import com.google.zxing.pdf417.decoder.PDF417ScanningDecoder;
32 import com.google.zxing.pdf417.detector.Detector;
33 import com.google.zxing.pdf417.detector.PDF417DetectorResult;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.Map;
38 
39 /**
40  * This implementation can detect and decode PDF417 codes in an image.
41  *
42  * @author Guenther Grau
43  */
44 public final class PDF417Reader implements Reader, MultipleBarcodeReader {
45 
46   private static final Result[] EMPTY_RESULT_ARRAY = new Result[0];
47 
48   /**
49    * Locates and decodes a PDF417 code in an image.
50    *
51    * @return a String representing the content encoded by the PDF417 code
52    * @throws NotFoundException if a PDF417 code cannot be found,
53    * @throws FormatException if a PDF417 cannot be decoded
54    */
55   @Override
decode(BinaryBitmap image)56   public Result decode(BinaryBitmap image) throws NotFoundException, FormatException, ChecksumException {
57     return decode(image, null);
58   }
59 
60   @Override
decode(BinaryBitmap image, Map<DecodeHintType,?> hints)61   public Result decode(BinaryBitmap image, Map<DecodeHintType,?> hints) throws NotFoundException, FormatException,
62       ChecksumException {
63     Result[] result = decode(image, hints, false);
64     if (result.length == 0 || result[0] == null) {
65       throw NotFoundException.getNotFoundInstance();
66     }
67     return result[0];
68   }
69 
70   @Override
decodeMultiple(BinaryBitmap image)71   public Result[] decodeMultiple(BinaryBitmap image) throws NotFoundException {
72     return decodeMultiple(image, null);
73   }
74 
75   @Override
decodeMultiple(BinaryBitmap image, Map<DecodeHintType,?> hints)76   public Result[] decodeMultiple(BinaryBitmap image, Map<DecodeHintType,?> hints) throws NotFoundException {
77     try {
78       return decode(image, hints, true);
79     } catch (FormatException | ChecksumException ignored) {
80       throw NotFoundException.getNotFoundInstance();
81     }
82   }
83 
decode(BinaryBitmap image, Map<DecodeHintType, ?> hints, boolean multiple)84   private static Result[] decode(BinaryBitmap image, Map<DecodeHintType, ?> hints, boolean multiple)
85       throws NotFoundException, FormatException, ChecksumException {
86     List<Result> results = new ArrayList<>();
87     PDF417DetectorResult detectorResult = Detector.detect(image, hints, multiple);
88     for (ResultPoint[] points : detectorResult.getPoints()) {
89       DecoderResult decoderResult = PDF417ScanningDecoder.decode(detectorResult.getBits(), points[4], points[5],
90           points[6], points[7], getMinCodewordWidth(points), getMaxCodewordWidth(points));
91       Result result = new Result(decoderResult.getText(), decoderResult.getRawBytes(), points, BarcodeFormat.PDF_417);
92       result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.getECLevel());
93       result.putMetadata(ResultMetadataType.ERRORS_CORRECTED, decoderResult.getErrorsCorrected());
94       result.putMetadata(ResultMetadataType.ERASURES_CORRECTED, decoderResult.getErasures());
95       PDF417ResultMetadata pdf417ResultMetadata = (PDF417ResultMetadata) decoderResult.getOther();
96       if (pdf417ResultMetadata != null) {
97         result.putMetadata(ResultMetadataType.PDF417_EXTRA_METADATA, pdf417ResultMetadata);
98       }
99       result.putMetadata(ResultMetadataType.ORIENTATION, detectorResult.getRotation());
100       result.putMetadata(ResultMetadataType.SYMBOLOGY_IDENTIFIER, "]L" + decoderResult.getSymbologyModifier());
101       results.add(result);
102     }
103     return results.toArray(EMPTY_RESULT_ARRAY);
104   }
105 
getMaxWidth(ResultPoint p1, ResultPoint p2)106   private static int getMaxWidth(ResultPoint p1, ResultPoint p2) {
107     if (p1 == null || p2 == null) {
108       return 0;
109     }
110     return (int) Math.abs(p1.getX() - p2.getX());
111   }
112 
getMinWidth(ResultPoint p1, ResultPoint p2)113   private static int getMinWidth(ResultPoint p1, ResultPoint p2) {
114     if (p1 == null || p2 == null) {
115       return Integer.MAX_VALUE;
116     }
117     return (int) Math.abs(p1.getX() - p2.getX());
118   }
119 
getMaxCodewordWidth(ResultPoint[] p)120   private static int getMaxCodewordWidth(ResultPoint[] p) {
121     return Math.max(
122         Math.max(getMaxWidth(p[0], p[4]), getMaxWidth(p[6], p[2]) * PDF417Common.MODULES_IN_CODEWORD /
123             PDF417Common.MODULES_IN_STOP_PATTERN),
124         Math.max(getMaxWidth(p[1], p[5]), getMaxWidth(p[7], p[3]) * PDF417Common.MODULES_IN_CODEWORD /
125             PDF417Common.MODULES_IN_STOP_PATTERN));
126   }
127 
getMinCodewordWidth(ResultPoint[] p)128   private static int getMinCodewordWidth(ResultPoint[] p) {
129     return Math.min(
130         Math.min(getMinWidth(p[0], p[4]), getMinWidth(p[6], p[2]) * PDF417Common.MODULES_IN_CODEWORD /
131             PDF417Common.MODULES_IN_STOP_PATTERN),
132         Math.min(getMinWidth(p[1], p[5]), getMinWidth(p[7], p[3]) * PDF417Common.MODULES_IN_CODEWORD /
133             PDF417Common.MODULES_IN_STOP_PATTERN));
134   }
135 
136   @Override
reset()137   public void reset() {
138     // nothing needs to be reset
139   }
140 
141 }
142