• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 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.maxicode;
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.BitMatrix;
30 import com.google.zxing.common.DecoderResult;
31 import com.google.zxing.maxicode.decoder.Decoder;
32 
33 import java.util.Map;
34 
35 /**
36  * This implementation can detect and decode a MaxiCode in an image.
37  */
38 public final class MaxiCodeReader implements Reader {
39 
40   private static final ResultPoint[] NO_POINTS = new ResultPoint[0];
41   private static final int MATRIX_WIDTH = 30;
42   private static final int MATRIX_HEIGHT = 33;
43 
44   private final Decoder decoder = new Decoder();
45 
46   /**
47    * Locates and decodes a MaxiCode in an image.
48    *
49    * @return a String representing the content encoded by the MaxiCode
50    * @throws NotFoundException if a MaxiCode cannot be found
51    * @throws FormatException if a MaxiCode cannot be decoded
52    * @throws ChecksumException if error correction fails
53    */
54   @Override
decode(BinaryBitmap image)55   public Result decode(BinaryBitmap image) throws NotFoundException, ChecksumException, FormatException {
56     return decode(image, null);
57   }
58 
59   @Override
decode(BinaryBitmap image, Map<DecodeHintType,?> hints)60   public Result decode(BinaryBitmap image, Map<DecodeHintType,?> hints)
61       throws NotFoundException, ChecksumException, FormatException {
62     // Note that MaxiCode reader effectively always assumes PURE_BARCODE mode
63     // and can't detect it in an image
64     BitMatrix bits = extractPureBits(image.getBlackMatrix());
65     DecoderResult decoderResult = decoder.decode(bits, hints);
66     Result result = new Result(decoderResult.getText(), decoderResult.getRawBytes(), NO_POINTS, BarcodeFormat.MAXICODE);
67     result.putMetadata(ResultMetadataType.ERRORS_CORRECTED, decoderResult.getErrorsCorrected());
68     String ecLevel = decoderResult.getECLevel();
69     if (ecLevel != null) {
70       result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel);
71     }
72     return result;
73   }
74 
75   @Override
reset()76   public void reset() {
77     // do nothing
78   }
79 
80   /**
81    * This method detects a code in a "pure" image -- that is, pure monochrome image
82    * which contains only an unrotated, unskewed, image of a code, with some white border
83    * around it. This is a specialized method that works exceptionally fast in this special
84    * case.
85    */
extractPureBits(BitMatrix image)86   private static BitMatrix extractPureBits(BitMatrix image) throws NotFoundException {
87 
88     int[] enclosingRectangle = image.getEnclosingRectangle();
89     if (enclosingRectangle == null) {
90       throw NotFoundException.getNotFoundInstance();
91     }
92 
93     int left = enclosingRectangle[0];
94     int top = enclosingRectangle[1];
95     int width = enclosingRectangle[2];
96     int height = enclosingRectangle[3];
97 
98     // Now just read off the bits
99     BitMatrix bits = new BitMatrix(MATRIX_WIDTH, MATRIX_HEIGHT);
100     for (int y = 0; y < MATRIX_HEIGHT; y++) {
101       int iy = Math.min(top + (y * height + height / 2) / MATRIX_HEIGHT, height - 1);
102       for (int x = 0; x < MATRIX_WIDTH; x++) {
103         // srowen: I don't quite understand why the formula below is necessary, but it
104         // can walk off the image if left + width = the right boundary. So cap it.
105         int ix = left + Math.min(
106             (x * width + width / 2 + (y & 0x01) * width / 2) / MATRIX_WIDTH,
107             width - 1);
108         if (image.get(ix, iy)) {
109           bits.set(x, y);
110         }
111       }
112     }
113     return bits;
114   }
115 
116 }
117