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