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