content: /*
   * Copyright 2007 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.
   */
  
  package com.ailiwean.core.zxing.core.datamatrix;
  
  
  import com.ailiwean.core.zxing.core.BarcodeFormat;
  import com.ailiwean.core.zxing.core.BinaryBitmap;
  import com.ailiwean.core.zxing.core.ChecksumException;
  import com.ailiwean.core.zxing.core.DecodeHintType;
  import com.ailiwean.core.zxing.core.FormatException;
  import com.ailiwean.core.zxing.core.NotFoundException;
  import com.ailiwean.core.zxing.core.Reader;
  import com.ailiwean.core.zxing.core.Result;
  import com.ailiwean.core.zxing.core.ResultMetadataType;
  import com.ailiwean.core.zxing.core.ResultPoint;
  import com.ailiwean.core.zxing.core.common.BitMatrix;
  import com.ailiwean.core.zxing.core.common.DecoderResult;
  import com.ailiwean.core.zxing.core.common.DetectorResult;
  import com.ailiwean.core.zxing.core.datamatrix.decoder.Decoder;
  import com.ailiwean.core.zxing.core.datamatrix.detector.Detector;
  
  import java.util.List;
  import java.util.Map;
  
  /**
   * This implementation can detect and decode Data Matrix codes in an image.
   *
   * @author bbrown@google.com (Brian Brown)
   */
  public final class DataMatrixReader implements Reader {
  
    private static final ResultPoint[] NO_POINTS = new ResultPoint[0];
  
    private final Decoder decoder = new Decoder();
  
    /**
     * Locates and decodes a Data Matrix code in an image.
     *
     * @return a String representing the content encoded by the Data Matrix code
     * @throws NotFoundException if a Data Matrix code cannot be found
     * @throws FormatException if a Data Matrix code cannot be decoded
     * @throws ChecksumException if error correction fails
     */
    @Override
    public Result decode(BinaryBitmap image) throws NotFoundException, ChecksumException, FormatException {
      return decode(image, null);
    }
  
    @Override
    public Result decode(BinaryBitmap image, Map<DecodeHintType,?> hints)
        throws NotFoundException, ChecksumException, FormatException {
      DecoderResult decoderResult;
      ResultPoint[] points;
      if (hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE)) {
        BitMatrix bits = extractPureBits(image.getBlackMatrix());
        decoderResult = decoder.decode(bits);
        points = NO_POINTS;
      } else {
        DetectorResult detectorResult = new Detector(image.getBlackMatrix()).detect();
        decoderResult = decoder.decode(detectorResult.getBits());
        points = detectorResult.getPoints();
      }
      Result result = new Result(decoderResult.getText(), decoderResult.getRawBytes(), points,
          BarcodeFormat.DATA_MATRIX);
      List<byte[]> byteSegments = decoderResult.getByteSegments();
      if (byteSegments != null) {
        result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments);
      }
      String ecLevel = decoderResult.getECLevel();
      if (ecLevel != null) {
        result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel);
      }
      return result;
    }
  
    @Override
    public void reset() {
      // do nothing
    }
  
    /**
     * This method detects a code in a "pure" image -- that is, pure monochrome image
     * which contains only an unrotated, unskewed, image of a code, with some white border
     * around it. This is a specialized method that works exceptionally fast in this special
     * case.
     */
    private static BitMatrix extractPureBits(BitMatrix image) throws NotFoundException {
  
      int[] leftTopBlack = image.getTopLeftOnBit();
      int[] rightBottomBlack = image.getBottomRightOnBit();
      if (leftTopBlack == null || rightBottomBlack == null) {
        throw NotFoundException.getNotFoundInstance();
      }
  
      int moduleSize = moduleSize(leftTopBlack, image);
  
      int top = leftTopBlack[1];
      int bottom = rightBottomBlack[1];
      int left = leftTopBlack[0];
      int right = rightBottomBlack[0];
  
      int matrixWidth = (right - left + 1) / moduleSize;
      int matrixHeight = (bottom - top + 1) / moduleSize;
      if (matrixWidth <= 0 || matrixHeight <= 0) {
        throw NotFoundException.getNotFoundInstance();
      }
  
      // Push in the "border" by half the module width so that we start
      // sampling in the middle of the module. Just in case the image is a
      // little off, this will help recover.
      int nudge = moduleSize / 2;
      top += nudge;
      left += nudge;
  
      // Now just read off the bits
      BitMatrix bits = new BitMatrix(matrixWidth, matrixHeight);
      for (int y = 0; y < matrixHeight; y++) {
        int iOffset = top + y * moduleSize;
        for (int x = 0; x < matrixWidth; x++) {
          if (image.get(left + x * moduleSize, iOffset)) {
            bits.set(x, y);
          }
        }
      }
      return bits;
    }
  
    private static int moduleSize(int[] leftTopBlack, BitMatrix image) throws NotFoundException {
      int width = image.getWidth();
      int x = leftTopBlack[0];
      int y = leftTopBlack[1];
      while (x < width && image.get(x, y)) {
        x++;
      }
      if (x == width) {
        throw NotFoundException.getNotFoundInstance();
      }
  
      int moduleSize = x - leftTopBlack[0];
      if (moduleSize == 0) {
        throw NotFoundException.getNotFoundInstance();
      }
      return moduleSize;
    }
  
  }
  