X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=core%2Fsrc%2Fcom%2Fgoogle%2Fzxing%2Fqrcode%2Fdecoder%2FDecoder.java;h=520e076f9e4d43c39b9dd560329864ef5ae17ec7;hb=HEAD;hp=a37128f53d78bf6eec79aefd1d15ec04c72a70db;hpb=9dc2a42f1e2a05cd525d4e583e6127eda8e7c4de;p=zxing.git diff --git a/core/src/com/google/zxing/qrcode/decoder/Decoder.java b/core/src/com/google/zxing/qrcode/decoder/Decoder.java index a37128f5..520e076f 100644 --- a/core/src/com/google/zxing/qrcode/decoder/Decoder.java +++ b/core/src/com/google/zxing/qrcode/decoder/Decoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Google Inc. + * 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. @@ -16,44 +16,91 @@ package com.google.zxing.qrcode.decoder; -import com.google.zxing.ReaderException; +import com.google.zxing.ChecksumException; +import com.google.zxing.FormatException; +import com.google.zxing.NotFoundException; import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.DecoderResult; +import com.google.zxing.common.reedsolomon.GF256; import com.google.zxing.common.reedsolomon.ReedSolomonDecoder; import com.google.zxing.common.reedsolomon.ReedSolomonException; +import java.util.Hashtable; + /** - * @author srowen@google.com (Sean Owen) + *

The main class which implements QR Code decoding -- as opposed to locating and extracting + * the QR Code from an image.

+ * + * @author Sean Owen */ public final class Decoder { - private Decoder() { + private final ReedSolomonDecoder rsDecoder; + + public Decoder() { + rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD); } - public static String decode(boolean[][] image) throws ReaderException { + public DecoderResult decode(boolean[][] image) + throws ChecksumException, FormatException, NotFoundException { + return decode(image, null); + } + + /** + *

Convenience method that can decode a QR Code represented as a 2D array of booleans. + * "true" is taken to mean a black module.

+ * + * @param image booleans representing white/black QR Code modules + * @return text and bytes encoded within the QR Code + * @throws FormatException if the QR Code cannot be decoded + * @throws ChecksumException if error correction fails + */ + public DecoderResult decode(boolean[][] image, Hashtable hints) throws ChecksumException, FormatException { int dimension = image.length; BitMatrix bits = new BitMatrix(dimension); for (int i = 0; i < dimension; i++) { for (int j = 0; j < dimension; j++) { if (image[i][j]) { - bits.set(i, j); + bits.set(j, i); } } } - return decode(bits); + return decode(bits, hints); } - public static String decode(BitMatrix bits) throws ReaderException { + public DecoderResult decode(BitMatrix bits) throws ChecksumException, FormatException { + return decode(bits, null); + } + + /** + *

Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.

+ * + * @param bits booleans representing white/black QR Code modules + * @return text and bytes encoded within the QR Code + * @throws FormatException if the QR Code cannot be decoded + * @throws ChecksumException if error correction fails + */ + public DecoderResult decode(BitMatrix bits, Hashtable hints) throws FormatException, ChecksumException { + + // Construct a parser and read version, error-correction level BitMatrixParser parser = new BitMatrixParser(bits); Version version = parser.readVersion(); ErrorCorrectionLevel ecLevel = parser.readFormatInformation().getErrorCorrectionLevel(); + + // Read codewords byte[] codewords = parser.readCodewords(); + // Separate into data blocks DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel); + + // Count total number of data bytes int totalBytes = 0; for (int i = 0; i < dataBlocks.length; i++) { totalBytes += dataBlocks[i].getNumDataCodewords(); } byte[] resultBytes = new byte[totalBytes]; int resultOffset = 0; + + // Error-correct and copy data blocks together into a stream of bytes for (int j = 0; j < dataBlocks.length; j++) { DataBlock dataBlock = dataBlocks[j]; byte[] codewordBytes = dataBlock.getCodewords(); @@ -64,22 +111,33 @@ public final class Decoder { } } - return DecodedBitStreamParser.decode(resultBytes, version); + // Decode the contents of that stream of bytes + return DecodedBitStreamParser.decode(resultBytes, version, ecLevel, hints); } - private static void correctErrors(byte[] codewordBytes, int numDataCodewords) - throws ReaderException { + /** + *

Given data and error-correction codewords received, possibly corrupted by errors, attempts to + * correct the errors in-place using Reed-Solomon error correction.

+ * + * @param codewordBytes data and error correction codewords + * @param numDataCodewords number of codewords that are data bytes + * @throws ChecksumException if error correction fails + */ + private void correctErrors(byte[] codewordBytes, int numDataCodewords) throws ChecksumException { int numCodewords = codewordBytes.length; + // First read into an array of ints int[] codewordsInts = new int[numCodewords]; for (int i = 0; i < numCodewords; i++) { codewordsInts[i] = codewordBytes[i] & 0xFF; } int numECCodewords = codewordBytes.length - numDataCodewords; try { - ReedSolomonDecoder.decode(codewordsInts, numECCodewords); + rsDecoder.decode(codewordsInts, numECCodewords); } catch (ReedSolomonException rse) { - throw new ReaderException(rse.toString()); + throw ChecksumException.getChecksumInstance(); } + // Copy back into array of bytes -- only need to worry about the bytes that were data + // We don't care about errors in the error-correction codewords for (int i = 0; i < numDataCodewords; i++) { codewordBytes[i] = (byte) codewordsInts[i]; }