+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing;
-
-/**
- * Enumerates barcode formats known to this package.
- *
- * @author srowen@google.com (Sean Owen)
- */
-public final class BarcodeFormat {
-
- // No, we can't use an enum here. J2ME doesn't support it.
-
- public static final BarcodeFormat UPC = new BarcodeFormat();
- public static final BarcodeFormat QR_CODE = new BarcodeFormat();
- public static final BarcodeFormat DATAMATRIX = new BarcodeFormat();
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing;
-
-/**
- * Encapsulates a type of hint that a caller may pass to a barcode reader to help it
- * more quickly or accurately decode it. It is up to implementations to decide what,
- * if anything, to do with the information that is supplied.
- *
- * @author srowen@google.com (Sean Owen), dswitkin@google.com (Daniel Switkin)
- * @see Reader#decode(MonochromeBitmapSource, java.util.Map)
- */
-public final class DecodeHintType {
-
- // No, we can't use an enum here. J2ME doesn't support it.
-
- /** Unspecified, application-specific hint. */
- public static final DecodeHintType OTHER = new DecodeHintType();
- /** Image is a pure monochrome image of a barcode. */
- public static final DecodeHintType PURE_BARCODE = new DecodeHintType();
- /**
- * Image is known to be of one of a few possible formats.
- * Maps to {@link java.util.Collection} of {@link BarcodeFormat}s.
- */
- public static final DecodeHintType POSSIBLE_FORMATS = new DecodeHintType();
-
- private DecodeHintType() {}
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing;
-
-import com.google.zxing.common.BitArray;
-
-/**
- * Encapsulates a generic black-and-white bitmap -- a collection of pixels in two dimensions.
- * This unifies many possible representations, like AWT's <code>BufferedImage</code>.
- *
- * @author srowen@google.com (Sean Owen)
- */
-public interface MonochromeBitmapSource {
-
- /**
- * @param x horizontal offset, from left, of the pixel
- * @param y vertical offset, from top, of the pixel
- * @return true iff the pixel at (x,y) is black
- */
- boolean isBlack(int x, int y);
-
- /**
- * Returns an entire row of black/white pixels as an array of bits, where "true" means "black".
- * This is a sort of "bulk get" operation intended to enable efficient access in
- * certain situations.
- *
- * @param y vertical offset, from top, of the row of pixels
- * @param row if not null, {@link BitArray} to write pixels into. If null, a new {@link BitArray}
- * is allocated and returned.
- * @param startX horizontal offset, from left, from which to start getting pixels
- * @param getWidth number of pixels to get from the row
- * @return {@link BitArray} representing the (subset of the) row of pixels. If row parameter
- * was not null, it is returned.
- */
- BitArray getBlackRow(int y, BitArray row, int startX, int getWidth);
-
- /**
- * @return height of underlying image
- */
- int getHeight();
-
- /**
- * @return width of underlying image
- */
- int getWidth();
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing;
-
-import com.google.zxing.qrcode.QRCodeReader;
-
-import java.util.Hashtable;
-
-/**
- * For now, only delegates to {@link QRCodeReader}.
- *
- * @author srowen@google.com (Sean Owen), dswitkin@google.com (Daniel Switkin)
- */
-public final class MultiFormatReader implements Reader {
-
- public Result decode(MonochromeBitmapSource image) throws ReaderException {
- return decode(image, null);
- }
-
- public Result decode(MonochromeBitmapSource image, Hashtable hints)
- throws ReaderException {
- Hashtable possibleFormats =
- hints == null ? null : (Hashtable) hints.get(DecodeHintType.POSSIBLE_FORMATS);
- if (possibleFormats == null || possibleFormats.contains(BarcodeFormat.QR_CODE)) {
- return new QRCodeReader().decode(image, hints);
- } else {
- throw new ReaderException();
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing;
-
-import java.util.Hashtable;
-
-/**
- * Implementations of this interface can decode an image of a barcode in some format into
- * the String it encodes. For example, {@link com.google.zxing.qrcode.QRCodeReader} can
- * decode a QR code. The decoder may optionally receive hints from the caller which may help
- * it decode more quickly or accurately.
- *
- * See {@link com.google.zxing.MultiFormatReader}, which attempts to determine what barcode
- * format is present within the image as well, and then decodes it accordingly.
- *
- * @author srowen@google.com (Sean Owen), dswitkin@google.com (Daniel Switkin)
- */
-public interface Reader {
-
- /**
- * Locates and decodes a barcode in some format within an image.
- *
- * @param image image of barcode to decode
- * @return String which the barcode encodes
- * @throws ReaderException if the barcode cannot be located or decoded for any reason
- */
- Result decode(MonochromeBitmapSource image) throws ReaderException;
-
- /**
- * Locates and decodes a barcode in some format within an image. This method also accepts
- * hints, each possibly associated to some data, which may help the implementation decode.
- *
- * @param image image of barcode to decode
- * @param hints passed as a {@link Hashtable} from {@link DecodeHintType} to aribtrary data. The
- * meaning of the data depends upon the hint type. The implementation may or may not do
- * anything with these hints.
- * @return String which the barcode encodes
- * @throws ReaderException if the barcode cannot be located or decoded for any reason
- */
- Result decode(MonochromeBitmapSource image, Hashtable hints) throws ReaderException;
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing;
-
-/**
- * The general exception class throw when something goes wrong during decoding of a barcode.
- * This includes, but is not limited to, failing checksums / error correction algorithms, being
- * unable to locate finder timing patterns, and so on.
- *
- * @author srowen@google.com (Sean Owen)
- */
-public final class ReaderException extends Exception {
-
- public ReaderException() {
- }
-
- public ReaderException(String message) {
- super(message);
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing;
-
-/**
- * <p>Encapsulates the result of decoding a barcode within an image.</p>
- *
- * @author srowen@google.com (Sean Owen)
- */
-public final class Result {
-
- private final String text;
- private final ResultPoint[] resultPoints;
-
- public Result(String text, ResultPoint[] resultPoints) {
- this.text = text;
- this.resultPoints = resultPoints;
- }
-
- /**
- * @return raw text encoded by the barcode, if any
- */
- public String getText() {
- return text;
- }
-
- /**
- * @return points related to the barcode in the image. These are typically points
- * identifying finder patterns or the corners of the barcode. The exact meaning is
- * specific to the type of barcode that was decoded.
- */
- public ResultPoint[] getResultPoints() {
- return resultPoints;
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing;
-
-/**
- * <p>Encapsulates a point of interest in an image containing a barcode. Typically, this
- * would be the location of a finder pattern or the corner of the barcode, for example.</p>
- *
- * @author srowen@google.com (Sean Owen)
- */
-public interface ResultPoint {
-
- float getX();
- float getY();
-
-}
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.google.zxing.common;\r
-\r
-/**\r
- * <p>A simple, fast array of bits, represented compactly by an array of ints internally.</p>\r
- *\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-public final class BitArray {\r
-\r
- private final int[] bits;\r
-\r
- public BitArray(int size) {\r
- int arraySize = size >> 5;\r
- if ((size & 0x1F) != 0) {\r
- arraySize++;\r
- }\r
- bits = new int[arraySize];\r
- }\r
-\r
- /**\r
- * @return true iff bit i is set\r
- */\r
- public boolean get(int i) {\r
- return (bits[i >> 5] & (1 << (i & 0x1F))) != 0;\r
- }\r
-\r
- /**\r
- * Sets bit i.\r
- */\r
- public void set(int i) {\r
- bits[i >> 5] |= 1 << (i & 0x1F);\r
- }\r
-\r
- public void setBulk(int i, int newBits) {\r
- bits[i >> 5] = newBits;\r
- }\r
-\r
- /**\r
- * Clears all bits.\r
- */\r
- public void clear() {\r
- int max = bits.length;\r
- for (int i = 0; i < max; i++) {\r
- bits[i] = 0;\r
- }\r
- }\r
-\r
- /**\r
- * @return underlying array of ints. The first element holds the first 32 bits, and the least\r
- * significant bit is bit 0.\r
- */\r
- public int[] getBitArray() {\r
- return bits;\r
- }\r
-\r
-}
\ No newline at end of file
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.google.zxing.common;\r
-\r
-/**\r
- * <p>Represnts a square matrix of bits. In function arguments below, i is the row position\r
- * and j the column position of a bit. The top left bit corresponds to i = 0 and j = 0.</p>\r
- *\r
- * <p>Internally the bits are represented in a compact 1-D array of 32-bit ints. The\r
- * ordering of bits is column-major; that is the bits in this array correspond to\r
- * j=0 and i=0..dimension-1 first, then j=1 and i=0..dimension-1, etc.</p>\r
- *\r
- * <p>Within each int, less-signficant bits correspond to lower values of i and higher rows.\r
- * That is, the top-left bit is the least significant bit of the first int.</p>\r
- *\r
- * <p>This class is a convenient wrapper around this representation, but also exposes the internal\r
- * array for efficient access and manipulation.</p>\r
- *\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-public final class BitMatrix {\r
-\r
- private final int dimension;\r
- private final int[] bits;\r
-\r
- public BitMatrix(int dimension) {\r
- if (dimension < 1) {\r
- throw new IllegalArgumentException("dimension must be at least 1");\r
- }\r
- this.dimension = dimension;\r
- int numBits = dimension * dimension;\r
- int arraySize = numBits >> 5; // one int per 32 bits\r
- if ((numBits & 0x1F) != 0) { // plus one more if there are leftovers\r
- arraySize++;\r
- }\r
- bits = new int[arraySize];\r
- }\r
-\r
- public boolean get(int i, int j) {\r
- int offset = i + dimension * j;\r
- return ((bits[offset >> 5] >>> (offset & 0x1F)) & 0x01) != 0;\r
- }\r
-\r
- public void set(int i, int j) {\r
- int offset = i + dimension * j;\r
- bits[offset >> 5] |= 1 << (offset & 0x1F);\r
- }\r
-\r
- public void setRegion(int topI, int leftJ, int height, int width) {\r
- if (topI < 0 || leftJ < 0) {\r
- throw new IllegalArgumentException("topI and leftJ must be nonnegative");\r
- }\r
- if (height < 1 || width < 1) {\r
- throw new IllegalArgumentException("height and width must be at least 1");\r
- }\r
- int maxJ = leftJ + width;\r
- int maxI = topI + height;\r
- if (maxI > dimension || maxJ > dimension) {\r
- throw new IllegalArgumentException(\r
- "topI + height and leftJ + width must be <= matrix dimension");\r
- }\r
- for (int j = leftJ; j < maxJ; j++) {\r
- int jOffset = dimension * j;\r
- for (int i = topI; i < maxI; i++) {\r
- int offset = i + jOffset;\r
- bits[offset >> 5] |= 1 << (offset & 0x1F);\r
- }\r
- }\r
- }\r
-\r
- public int getDimension() {\r
- return dimension;\r
- }\r
-\r
- public int[] getBits() {\r
- return bits;\r
- }\r
-\r
- /*\r
- public BufferedImage toBufferedImage() {\r
- BufferedImage image =\r
- new BufferedImage(dimension, dimension, BufferedImage.TYPE_BYTE_BINARY);\r
- for (int j = 0; j < dimension; j++) {\r
- for (int i = 0; i < dimension; i++) {\r
- image.setRGB(j, i, get(i, j) ? 0x00000000 : 0x00FFFFFF);\r
- }\r
- }\r
- return image;\r
- }\r
- */\r
-\r
-}\r
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.google.zxing.common;\r
-\r
-/**\r
- * <p>Encapsulates logic that estimates the optimal "black point", the luminance value\r
- * which is the best line between "white" and "black" in a grayscale image.</p>\r
- *\r
- * <p>TODO: Include reference to paper with similar ideas</p>\r
- *\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-public final class BlackPointEstimator {\r
-\r
- private BlackPointEstimator() {\r
- }\r
-\r
- /**\r
- * <p>Given an array of <em>counts</em> of luminance values (i.e. a histogram), this method\r
- * decides which bucket of values corresponds to the black point -- which bucket contains the\r
- * count of the brightest luminance values that should be considered "black".</p>\r
- *\r
- * @param luminanceBuckets an array of <em>counts</em> of luminance values\r
- * @return index within argument of bucket corresponding to brightest values which should be\r
- * considered "black"\r
- */\r
- public static int estimate(int[] luminanceBuckets) {\r
-\r
- int numBuckets = luminanceBuckets.length;\r
-\r
- // Find tallest peak in histogram\r
- int firstPeak = 0;\r
- int firstPeakSize = 0;\r
- for (int i = 0; i < numBuckets; i++) {\r
- if (luminanceBuckets[i] > firstPeakSize) {\r
- firstPeak = i;\r
- firstPeakSize = luminanceBuckets[i];\r
- }\r
- }\r
-\r
- // Find second-tallest peak -- well, another peak that is tall and not\r
- // so close to the first one\r
- int secondPeak = 0;\r
- int secondPeakScore = 0;\r
- for (int i = 0; i < numBuckets; i++) {\r
- int distanceToBiggest = i - firstPeak;\r
- // Encourage more distant second peaks by multiplying by square\r
- // of distance\r
- int score = luminanceBuckets[i] * distanceToBiggest * distanceToBiggest;\r
- if (score > secondPeakScore) {\r
- secondPeak = i;\r
- secondPeakScore = score;\r
- }\r
- }\r
-\r
- // Put firstPeak first\r
- if (firstPeak > secondPeak) {\r
- int temp = firstPeak;\r
- firstPeak = secondPeak;\r
- secondPeak = temp;\r
- }\r
-\r
- // Find a valley between them that is low and close to the midpoint of the two peaks\r
- int bestValley = firstPeak;\r
- int bestValleyScore = 0;\r
- for (int i = firstPeak + 1; i < secondPeak; i++) {\r
- // Encourage low valleys near the mid point between peaks\r
- int score = (firstPeakSize - luminanceBuckets[i]) *\r
- (i - firstPeak) * (secondPeak - i);\r
- if (score > bestValleyScore) {\r
- bestValley = i;\r
- bestValleyScore = score;\r
- }\r
- }\r
-\r
- return bestValley;\r
- }\r
-\r
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.common;
-
-import java.util.Vector;
-
-/**
- * This is basically a substitute for <code>java.util.Collections</code>.
- */
-public final class Collections {
-
- private Collections() {
- }
-
- /**
- * Sorts its argument (destructively) using insert sort; in the context of this package
- * insertion sort is simple and efficient given its relatively small inputs.
- *
- * @param vector
- * @param comparator
- */
- public static void insertionSort(Vector vector, Comparator comparator) {
- int max = vector.size();
- for (int i = 1; i < max; i++) {
- Object value = vector.elementAt(i);
- int j = i - 1;
- Object valueB;
- while (j >= 0 && comparator.compare((valueB = vector.elementAt(j)), value) > 0) {
- vector.setElementAt(valueB, j + 1);
- j--;
- }
- vector.setElementAt(value, j + 1);
- }
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.common;
-
-/**
- * This is merely a clone of <code>Comparator</code> since it is not available in
- * CLDC 1.1 / MIDP 2.0.
- */
-public interface Comparator {
-
- int compare(Object o1, Object o2);
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.common.reedsolomon;
-
-/**
- * <p>This class contains utility methods for performing mathematical operations over
- * the Galois Field GF(256). Operations use the primitive polynomial
- * x^8 + x^4 + x^3 + x^2 + 1 in calculations.</p>
- *
- * <p>Throughout this package, elements of GF(256) are represented as an <code>int</code>
- * for convenience and speed (but at the cost of memory).
- * Only the bottom 8 bits are really used.</p>
- *
- * @author srowen@google.com (Sean Owen)
- */
-final class GF256 {
-
- private static final int PRIMITIVE = 0x011D;
- private static final int[] exp = new int[256];
- private static final int[] log = new int[256];
- static {
- int x = 1;
- for (int i = 0; i < 256; i++) {
- exp[i] = x;
- x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
- if (x >= 0x100) {
- x ^= PRIMITIVE;
- }
- }
- for (int i = 0; i < 255; i++) {
- log[exp[i]] = i;
- }
- // log[0] == 0 but this should never be used
- }
-
- private GF256() {
- }
-
- /**
- * Addition and subtraction are the same in GF(256).
- */
- static int addOrSubtract(int a, int b) {
- return a ^ b;
- }
-
- static int exp(int a) {
- return exp[a];
- }
-
- static int log(int a) {
- if (a == 0) {
- throw new IllegalArgumentException();
- }
- return log[a];
- }
-
- /**
- * @return multiplicative inverse of a
- */
- static int inverse(int a) {
- if (a == 0) {
- throw new ArithmeticException();
- }
- return exp[255 - log[a]];
- }
-
- static int multiply(int a, int b) {
- if (a == 0 || b == 0) {
- return 0;
- }
- if (a == 1) {
- return b;
- }
- if (b == 1) {
- return a;
- }
- return exp[(log[a] + log[b]) % 255];
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.common.reedsolomon;
-
-/**
- * <p>Represents a polynomial whose coefficients are elements of GF(256).
- * Instances of this class are immutable.</p>
- *
- * <p>Much credit is due to William Rucklidge since portions of this code are an indirect
- * port of his C++ Reed-Solomon implementation.</p>
- *
- * @author srowen@google.com (Sean Owen)
- */
-final class GF256Poly {
-
- /** Polynimal representing the monomial 0. */
- static final GF256Poly ZERO = new GF256Poly(new int[] { 0 });
- /** Polynimal representing the monomial 1. */
- static final GF256Poly ONE = new GF256Poly(new int[] { 1 });
-
- private final int[] coefficients;
-
- /**
- * @param coefficients coefficients as ints representing elements of GF(256), arranged
- * from most significant (highest-power term) coefficient to least significant
- * @throws IllegalArgumentException if argument is null or empty,
- * or if leading coefficient is 0 and this is not a
- * constant polynomial (that is, it is not the monomial "0")
- */
- GF256Poly(int[] coefficients) {
- if (coefficients == null || coefficients.length == 0) {
- throw new IllegalArgumentException();
- }
- if (coefficients.length > 1 && coefficients[0] == 0) {
- // Leading term must be non-zero for anything except the constant polynomial "0"
- int firstNonZero = 1;
- while (firstNonZero < coefficients.length && coefficients[firstNonZero] == 0) {
- firstNonZero++;
- }
- if (firstNonZero == coefficients.length) {
- this.coefficients = ZERO.coefficients;
- } else {
- this.coefficients = new int[coefficients.length - firstNonZero];
- System.arraycopy(coefficients,
- firstNonZero,
- this.coefficients,
- 0,
- this.coefficients.length);
- }
- } else {
- this.coefficients = coefficients;
- }
- }
-
- /**
- * @return degree of this polynomial
- */
- int getDegree() {
- return coefficients.length - 1;
- }
-
- /**
- * @return true iff this polynomial is the monomial "0"
- */
- boolean isZero() {
- return coefficients[0] == 0;
- }
-
- /**
- * @return the monomial representing coefficient * x^degree
- */
- static GF256Poly buildMonomial(int degree, int coefficient) {
- if (degree < 0) {
- throw new IllegalArgumentException();
- }
- if (coefficient == 0) {
- return ZERO;
- }
- int[] coefficients = new int[degree + 1];
- coefficients[0] = coefficient;
- return new GF256Poly(coefficients);
- }
-
- /**
- * @return coefficient of x^degree term in this polynomial
- */
- int getCoefficient(int degree) {
- return coefficients[coefficients.length - 1 - degree];
- }
-
- /**
- * @return evaluation of this polynomial at a given point
- */
- int evaluateAt(int a) {
- if (a == 0) {
- // Just return the x^0 coefficient
- return getCoefficient(0);
- }
- final int size = coefficients.length;
- if (a == 1) {
- // Just the sum of the coefficients
- int result = 0;
- for (int i = 0; i < size; i++) {
- result = GF256.addOrSubtract(result, coefficients[i]);
- }
- return result;
- }
- int result = coefficients[0];
- for (int i = 1; i < size; i++) {
- result = GF256.addOrSubtract(GF256.multiply(a, result), coefficients[i]);
- }
- return result;
- }
-
- int evaluateFormatDerivativeAt(int a) {
- int degree = getDegree();
- if (degree == 0) {
- // Derivative of a constant is zero.
- return 0;
- }
-
- int aToTheI = 1;
- int sum = getCoefficient(1);
- int aSquared = GF256.multiply(a, a);
- for (int i = 2; i < degree; i += 2) {
- aToTheI = GF256.multiply(aSquared, aToTheI);
- sum = GF256.addOrSubtract(sum, GF256.multiply(aToTheI, getCoefficient(i + 1)));
- }
- return sum;
- }
-
- GF256Poly addOrSubtract(GF256Poly other) {
- if (isZero()) {
- return other;
- }
- if (other.isZero()) {
- return this;
- }
-
- int[] smallerCoefficients = this.coefficients;
- int[] largerCoefficients = other.coefficients;
- if (smallerCoefficients.length > largerCoefficients.length) {
- int[] temp = smallerCoefficients;
- smallerCoefficients = largerCoefficients;
- largerCoefficients = temp;
- }
- int[] sumDiff = new int[largerCoefficients.length];
- int lengthDiff = largerCoefficients.length - smallerCoefficients.length;
- // Copy high-order terms only found in higher-degree polynomial's coefficients
- System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
-
- for (int i = lengthDiff; i < largerCoefficients.length; i++) {
- sumDiff[i] = GF256.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
- }
-
- return new GF256Poly(sumDiff);
- }
-
- GF256Poly multiply(GF256Poly other) {
- if (isZero() || other.isZero()) {
- return ZERO;
- }
- int[] aCoefficients = this.coefficients;
- int aLength = aCoefficients.length;
- int[] bCoefficients = other.coefficients;
- int bLength = bCoefficients.length;
- int[] product = new int[aLength + bLength - 1];
- for (int i = 0; i < aLength; i++) {
- int aCoeff = aCoefficients[i];
- for (int j = 0; j < bLength; j++) {
- product[i + j] = GF256.addOrSubtract(product[i + j],
- GF256.multiply(aCoeff, bCoefficients[j]));
- }
- }
- return new GF256Poly(product);
- }
-
- GF256Poly multiply(int scalar) {
- if (scalar == 0) {
- return ZERO;
- }
- if (scalar == 1) {
- return this;
- }
- int size = coefficients.length;
- int[] product = new int[size];
- System.arraycopy(coefficients, 0, product, 0, size);
- for (int i = 0; i < size; i++) {
- product[i] = GF256.multiply(product[i], scalar);
- }
- return new GF256Poly(product);
- }
-
- GF256Poly multiplyByMonomial(int degree, int coefficient) {
- if (degree < 0) {
- throw new IllegalArgumentException();
- }
- if (coefficient == 0) {
- return ZERO;
- }
- int size = coefficients.length;
- int[] product = new int[size + degree];
- System.arraycopy(coefficients, 0, product, 0, size);
- for (int i = 0; i < size; i++) {
- product[i] = GF256.multiply(product[i], coefficient);
- }
- return new GF256Poly(product);
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.common.reedsolomon;
-
-import java.util.Vector;
-
-/**
- * <p>Implements Reed-Solomon decoding, as the name implies.</p>
- *
- * <p>The algorithm will not be explained here, but the following references were helpful
- * in creating this implementation:</p>
- *
- * <ul>
- * <li>Bruce Maggs.
- * <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/pscico-guyb/realworld/www/rs_decode.ps">
- * "Decoding Reed-Solomon Codes"</a> (see discussion of Forney's Formula)</li>
- * <li>J.I. Hall. <a href="www.mth.msu.edu/~jhall/classes/codenotes/GRS.pdf">
- * "Chapter 5. Generalized Reed-Solomon Codes"</a>
- * (see discussion of Euclidean algorithm)</li>
- * </ul>
- *
- * <p>Much credit is due to William Rucklidge since portions of this code are an indirect
- * port of his C++ Reed-Solomon implementation.</p>
- *
- * @author srowen@google.com (Sean Owen)
- */
-public final class ReedSolomonDecoder {
-
- private ReedSolomonDecoder() {
- }
-
- public static void decode(int[] received, int twoS) throws ReedSolomonException {
- GF256Poly poly = new GF256Poly(received);
- int[] syndromeCoefficients = new int[twoS];
- for (int i = 0; i < twoS; i++) {
- syndromeCoefficients[syndromeCoefficients.length - 1 - i] = poly.evaluateAt(GF256.exp(i));
- }
- GF256Poly syndrome = new GF256Poly(syndromeCoefficients);
- if (!syndrome.isZero()) { // Error
- GF256Poly[] sigmaOmega =
- runEuclideanAlgorithm(GF256Poly.buildMonomial(twoS, 1), syndrome, twoS);
- int[] errorLocations = findErrorLocations(sigmaOmega[0]);
- int[] errorMagnitudes = findErrorMagnitudes(sigmaOmega[1], errorLocations);
- for (int i = 0; i < errorLocations.length; i++) {
- int position = received.length - 1 - GF256.log(errorLocations[i]);
- received[position] = GF256.addOrSubtract(received[position], errorMagnitudes[i]);
- }
- }
- }
-
- private static GF256Poly[] runEuclideanAlgorithm(GF256Poly a, GF256Poly b, int R)
- throws ReedSolomonException {
- // Assume a's degree is >= b's
- if (a.getDegree() < b.getDegree()) {
- GF256Poly temp = a;
- a = b;
- b = temp;
- }
-
- GF256Poly rLast = a;
- GF256Poly r = b;
- GF256Poly sLast = GF256Poly.ONE;
- GF256Poly s = GF256Poly.ZERO;
- GF256Poly tLast = GF256Poly.ZERO;
- GF256Poly t = GF256Poly.ONE;
-
- // Run Euclidean algorithm until r's degree is less than R/2
- while (r.getDegree() >= R / 2) {
- GF256Poly rLastLast = rLast;
- GF256Poly sLastLast = sLast;
- GF256Poly tLastLast = tLast;
- rLast = r;
- sLast = s;
- tLast = t;
-
- // Divide rLastLast by rLast, with quotient in q and remainder in r
- if (rLast.isZero()) {
- // Oops, Euclidean algorithm already terminated?
- throw new ReedSolomonException("r_{i-1} was zero");
- }
- r = rLastLast;
- GF256Poly q = GF256Poly.ZERO;
- int denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree());
- int dltInverse = GF256.inverse(denominatorLeadingTerm);
- while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
- int degreeDiff = r.getDegree() - rLast.getDegree();
- int scale = GF256.multiply(r.getCoefficient(r.getDegree()), dltInverse);
- q = q.addOrSubtract(GF256Poly.buildMonomial(degreeDiff, scale));
- r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
- }
-
- s = q.multiply(sLast).addOrSubtract(sLastLast);
- t = q.multiply(tLast).addOrSubtract(tLastLast);
- }
-
- int sigmaTildeAtZero = t.getCoefficient(0);
- if (sigmaTildeAtZero == 0) {
- throw new ReedSolomonException("sigmaTilde(0) was zero");
- }
-
- int inverse = GF256.inverse(sigmaTildeAtZero);
- GF256Poly sigma = t.multiply(inverse);
- GF256Poly omega = r.multiply(inverse);
- return new GF256Poly[] { sigma, omega };
- }
-
- private static int[] findErrorLocations(GF256Poly errorLocator)
- throws ReedSolomonException {
- // This is a direct application of Chien's search
- Vector errorLocations = new Vector(3);
- for (int i = 1; i < 256; i++) {
- if (errorLocator.evaluateAt(i) == 0) {
- errorLocations.addElement(new Integer(GF256.inverse(i)));
- }
- }
- if (errorLocations.size() != errorLocator.getDegree()) {
- throw new ReedSolomonException("Error locator degree does not match number of roots");
- }
- int[] result = new int[errorLocations.size()]; // Can't use toArray() here
- for (int i = 0; i < result.length; i++) {
- result[i] = ((Integer) errorLocations.elementAt(i)).intValue();
- }
- return result;
- }
-
- private static int[] findErrorMagnitudes(GF256Poly errorEvaluator,
- int[] errorLocations) {
- // This is directly applying Forney's Formula
- int s = errorLocations.length;
- int[] result = new int[s];
- for (int i = 0; i < errorLocations.length; i++) {
- int xiInverse = GF256.inverse(errorLocations[i]);
- int denominator = 1;
- for (int j = 0; j < s; j++) {
- if (i != j) {
- denominator = GF256.multiply(denominator,
- GF256.addOrSubtract(1, GF256.multiply(errorLocations[j], xiInverse)));
- }
- }
- result[i] = GF256.multiply(errorEvaluator.evaluateAt(xiInverse),
- GF256.inverse(denominator));
- }
- return result;
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.common.reedsolomon;
-
-/**
- * <p>Thrown when an exception occurs during Reed-Solomon decoding, such as when
- * there are too many errors to correct.</p>
- *
- * @author srowen@google.com (Sean Owen)
- */
-public final class ReedSolomonException extends Exception {
-
- public ReedSolomonException() {
- }
-
- public ReedSolomonException(String message) {
- super(message);
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode;
-
-import com.google.zxing.DecodeHintType;
-import com.google.zxing.MonochromeBitmapSource;
-import com.google.zxing.Reader;
-import com.google.zxing.ReaderException;
-import com.google.zxing.Result;
-import com.google.zxing.ResultPoint;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.qrcode.decoder.Decoder;
-import com.google.zxing.qrcode.detector.Detector;
-import com.google.zxing.qrcode.detector.DetectorResult;
-
-import java.util.Hashtable;
-
-/**
- * @author srowen@google.com (Sean Owen)
- */
-public final class QRCodeReader implements Reader {
-
- /**
- * Locates and decodes a QR code in an image.
- *
- * @return a String representing the content encoded by the QR code
- * @throws ReaderException if a QR code cannot be found, or cannot be decoded
- */
- public Result decode(MonochromeBitmapSource image) throws ReaderException {
- return decode(image, null);
- }
-
- public Result decode(MonochromeBitmapSource image, Hashtable hints)
- throws ReaderException {
- String text;
- ResultPoint[] points;
- if (hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE)) {
- BitMatrix bits = extractPureBits(image);
- text = Decoder.decode(bits);
- points = new ResultPoint[0];
- } else {
- DetectorResult result = new Detector(image).detect();
- text = Decoder.decode(result.getBits());
- points = result.getPoints();
- }
- return new Result(text, points);
- }
-
- private static BitMatrix extractPureBits(MonochromeBitmapSource image)
- throws ReaderException {
- // Now need to determine module size in pixels
- // First, skip white border
- int borderWidth = 0;
- while (!image.isBlack(borderWidth, borderWidth)) {
- borderWidth++;
- }
- int moduleEnd = borderWidth;
- while (image.isBlack(moduleEnd, moduleEnd)) {
- moduleEnd++;
- }
- int moduleSize = moduleEnd - borderWidth;
-
- int rowEndOfSymbol = image.getWidth() - 1;
- while (!image.isBlack(rowEndOfSymbol, borderWidth)) {
- rowEndOfSymbol--;
- }
- rowEndOfSymbol++;
-
- if ((rowEndOfSymbol - borderWidth) % moduleSize != 0) {
- throw new ReaderException("Bad module size / width: " + moduleSize +
- " / " + (rowEndOfSymbol - borderWidth));
- }
- int dimension = (rowEndOfSymbol - borderWidth) / moduleSize;
-
- // 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.
- borderWidth += moduleSize >> 1;
-
- BitMatrix bits = new BitMatrix(dimension);
- for (int i = 0; i < dimension; i++) {
- int iOffset = borderWidth + i * moduleSize;
- for (int j = 0; j < dimension; j++) {
- if (image.isBlack(borderWidth + j * moduleSize, iOffset)) {
- bits.set(i, j);
- }
- }
- }
- return bits;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.google.zxing.qrcode.decoder;\r
-\r
-import com.google.zxing.ReaderException;\r
-import com.google.zxing.common.BitMatrix;\r
-\r
-/**\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-final class BitMatrixParser {\r
-\r
- private final BitMatrix bitMatrix;\r
- private Version parsedVersion;\r
- private FormatInformation parsedFormatInfo;\r
-\r
- /**\r
- * @throws com.google.zxing.ReaderException\r
- * if dimension is not >= 21 and 1 mod 4\r
- */\r
- BitMatrixParser(BitMatrix bitMatrix) throws ReaderException {\r
- int dimension = bitMatrix.getDimension();\r
- if (dimension < 21 || (dimension & 0x03) != 1) {\r
- throw new ReaderException("Dimension must be 1 mod 4 and >= 21");\r
- }\r
- this.bitMatrix = bitMatrix;\r
- }\r
-\r
- FormatInformation readFormatInformation() throws ReaderException {\r
-\r
- if (parsedFormatInfo != null) {\r
- return parsedFormatInfo;\r
- }\r
-\r
- // Read top-left format info bits\r
- int formatInfoBits = 0;\r
- for (int j = 0; j < 6; j++) {\r
- formatInfoBits = copyBit(8, j, formatInfoBits);\r
- }\r
- // .. and skip a bit in the timing pattern ...\r
- formatInfoBits = copyBit(8, 7, formatInfoBits);\r
- formatInfoBits = copyBit(8, 8, formatInfoBits);\r
- formatInfoBits = copyBit(7, 8, formatInfoBits);\r
- // .. and skip a bit in the timing pattern ...\r
- for (int i = 5; i >= 0; i--) {\r
- formatInfoBits = copyBit(i, 8, formatInfoBits);\r
- }\r
-\r
- parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);\r
- if (parsedFormatInfo != null) {\r
- return parsedFormatInfo;\r
- }\r
-\r
- // Hmm, failed. Try the top-right/bottom-left pattern\r
- int dimension = bitMatrix.getDimension();\r
- formatInfoBits = 0;\r
- int iMin = dimension - 8;\r
- for (int i = dimension - 1; i >= iMin; i--) {\r
- formatInfoBits = copyBit(i, 8, formatInfoBits);\r
- }\r
- for (int j = dimension - 7; j < dimension; j++) {\r
- formatInfoBits = copyBit(8, j, formatInfoBits);\r
- }\r
-\r
- parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);\r
- if (parsedFormatInfo != null) {\r
- return parsedFormatInfo;\r
- }\r
- throw new ReaderException("Could not decode format information");\r
- }\r
-\r
- Version readVersion() throws ReaderException {\r
-\r
- if (parsedVersion != null) {\r
- return parsedVersion;\r
- }\r
-\r
- int dimension = bitMatrix.getDimension();\r
-\r
- int provisionalVersion = (dimension - 17) >> 2;\r
- if (provisionalVersion <= 6) {\r
- return Version.getVersionForNumber(provisionalVersion);\r
- }\r
-\r
- // Read top-right version info: 3 wide by 6 tall\r
- int versionBits = 0;\r
- for (int i = 5; i >= 0; i--) {\r
- int jMin = dimension - 11;\r
- for (int j = dimension - 9; j >= jMin; j--) {\r
- versionBits = copyBit(i, j, versionBits);\r
- }\r
- }\r
-\r
- parsedVersion = Version.decodeVersionInformation(versionBits);\r
- if (parsedVersion != null) {\r
- return parsedVersion;\r
- }\r
-\r
- // Hmm, failed. Try bottom left: 6 wide by 3 tall\r
- versionBits = 0;\r
- for (int j = 5; j >= 0; j--) {\r
- int iMin = dimension - 11;\r
- for (int i = dimension - 11; i >= iMin; i--) {\r
- versionBits = copyBit(i, j, versionBits);\r
- }\r
- }\r
-\r
- parsedVersion = Version.decodeVersionInformation(versionBits);\r
- if (parsedVersion != null) {\r
- return parsedVersion;\r
- }\r
- throw new ReaderException("Could not decode version");\r
- }\r
-\r
- private int copyBit(int i, int j, int versionBits) {\r
- return bitMatrix.get(i, j) ? (versionBits << 1) | 0x1 : versionBits << 1;\r
- }\r
-\r
- byte[] readCodewords() throws ReaderException {\r
-\r
- FormatInformation formatInfo = readFormatInformation();\r
- Version version = readVersion();\r
-\r
- DataMask dataMask = DataMask.forReference((int) formatInfo.getDataMask());\r
- int dimension = bitMatrix.getDimension();\r
- dataMask.unmaskBitMatrix(bitMatrix.getBits(), dimension);\r
-\r
- BitMatrix functionPattern = version.buildFunctionPattern();\r
-\r
- boolean readingUp = true;\r
- byte[] result = new byte[version.getTotalCodewords()];\r
- int resultOffset = 0;\r
- int currentByte = 0;\r
- int bitsRead = 0;\r
- for (int j = dimension - 1; j > 0; j -= 2) {\r
- if (j == 6) {\r
- // Skip whole column with vertical alignment pattern;\r
- // saves time and makes the other code proceed more cleanly\r
- j--;\r
- }\r
- for (int count = 0; count < dimension; count++) {\r
- int i = readingUp ? dimension - 1 - count : count;\r
- for (int col = 0; col < 2; col++) {\r
- if (!functionPattern.get(i, j - col)) {\r
- bitsRead++;\r
- currentByte <<= 1;\r
- if (bitMatrix.get(i, j - col)) {\r
- currentByte |= 1;\r
- }\r
- if (bitsRead == 8) {\r
- result[resultOffset++] = (byte) currentByte;\r
- bitsRead = 0;\r
- currentByte = 0;\r
- }\r
- }\r
- }\r
- }\r
- readingUp = !readingUp; // switch directions\r
- }\r
- if (resultOffset != version.getTotalCodewords()) {\r
- throw new ReaderException("Did not read all codewords");\r
- }\r
- return result;\r
- }\r
-\r
-}
\ No newline at end of file
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.google.zxing.qrcode.decoder;\r
-\r
-/**\r
- * This provides an easy abstraction to read bits at a time from a sequence of bytes, where the\r
- * number of bits read is not often a multiple of 8.\r
- *\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-final class BitSource {\r
-\r
- private final byte[] bytes;\r
- private int byteOffset;\r
- private int bitOffset;\r
-\r
- BitSource(byte[] bytes) {\r
- this.bytes = bytes;\r
- }\r
-\r
- /**\r
- * @throws IllegalArgumentException if numBits isn't in [1,32]\r
- */\r
- int readBits(int numBits) {\r
- if (numBits < 1 || numBits > 32) {\r
- throw new IllegalArgumentException();\r
- }\r
-\r
- int result = 0;\r
-\r
- // First, read remainder from current byte\r
- if (bitOffset > 0) {\r
- int bitsLeft = 8 - bitOffset;\r
- int toRead = numBits < bitsLeft ? numBits : bitsLeft;\r
- int bitsToNotRead = bitsLeft - toRead;\r
- int mask = (0xFF >> (8 - toRead)) << bitsToNotRead;\r
- result = (bytes[byteOffset] & mask) >> bitsToNotRead;\r
- numBits -= toRead;\r
- bitOffset += toRead;\r
- if (bitOffset == 8) {\r
- bitOffset = 0;\r
- byteOffset++;\r
- }\r
- }\r
-\r
- // Next read whole bytes\r
- if (numBits > 0) {\r
- while (numBits >= 8) {\r
- result = (result << 8) | (bytes[byteOffset] & 0xFF);\r
- byteOffset++;\r
- numBits -= 8;\r
- }\r
-\r
- // Finally read a partial byte\r
- if (numBits > 0) {\r
- int bitsToNotRead = 8 - numBits;\r
- int mask = (0xFF >> bitsToNotRead) << bitsToNotRead;\r
- result = (result << numBits) | ((bytes[byteOffset] & mask) >> bitsToNotRead);\r
- bitOffset += numBits;\r
- }\r
- }\r
-\r
- return result;\r
- }\r
-\r
- int available() {\r
- return 8 * (bytes.length - byteOffset) - bitOffset;\r
- }\r
-\r
-}\r
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.google.zxing.qrcode.decoder;\r
-\r
-/**\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-final class DataBlock {\r
-\r
- private final int numDataCodewords;\r
- private final byte[] codewords;\r
-\r
- private DataBlock(int numDataCodewords, byte[] codewords) {\r
- this.numDataCodewords = numDataCodewords;\r
- this.codewords = codewords;\r
- }\r
-\r
- static DataBlock[] getDataBlocks(byte[] rawCodewords,\r
- Version version,\r
- ErrorCorrectionLevel ecLevel) {\r
- Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);\r
- int totalBlocks = 0;\r
- Version.ECB[] ecBlockArray = ecBlocks.getECBlocks();\r
- for (int i = 0; i < ecBlockArray.length; i++) {\r
- totalBlocks += ecBlockArray[i].getCount();\r
- }\r
- DataBlock[] result = new DataBlock[totalBlocks];\r
- int numResultBlocks = 0;\r
- for (int j = 0; j < ecBlockArray.length; j++) {\r
- Version.ECB ecBlock = ecBlockArray[j];\r
- for (int i = 0; i < ecBlock.getCount(); i++) {\r
- int numDataCodewords = ecBlock.getDataCodewords();\r
- int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords;\r
- result[numResultBlocks++] =\r
- new DataBlock(numDataCodewords, new byte[numBlockCodewords]);\r
- }\r
- }\r
-\r
- // All blocks have the same amount of data, except that the last n\r
- // (where n may be 0) have 1 more byte. Figure out where these start.\r
- int shorterBlocksTotalCodewords = result[0].codewords.length;\r
- int longerBlocksStartAt = result.length - 1;\r
- while (longerBlocksStartAt >= 0) {\r
- int numCodewords =\r
- result[longerBlocksStartAt].codewords.length;\r
- if (numCodewords == shorterBlocksTotalCodewords) {\r
- break;\r
- }\r
- if (numCodewords != shorterBlocksTotalCodewords + 1) {\r
- throw new IllegalStateException(\r
- "Data block sizes differ by more than 1");\r
- }\r
- longerBlocksStartAt--;\r
- }\r
- longerBlocksStartAt++;\r
-\r
- int shorterBlocksNumDataCodewords =\r
- shorterBlocksTotalCodewords - ecBlocks.getECCodewords();\r
- // The last elements of result may be 1 element longer;\r
- // first fill out as many elements as all of them have\r
- int rawCodewordsOffset = 0;\r
- for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {\r
- for (int j = 0; j < numResultBlocks; j++) {\r
- result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];\r
- }\r
- }\r
- // Fill out the last data block in the longer ones\r
- for (int j = longerBlocksStartAt; j < numResultBlocks; j++) {\r
- result[j].codewords[shorterBlocksNumDataCodewords] =\r
- rawCodewords[rawCodewordsOffset++];\r
- }\r
- // Now add in error correction blocks\r
- int max = result[0].codewords.length;\r
- for (int i = shorterBlocksNumDataCodewords; i < max; i++) {\r
- for (int j = 0; j < numResultBlocks; j++) {\r
- int iOffset = j < longerBlocksStartAt ? i : i + 1;\r
- result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];\r
- }\r
- }\r
-\r
- if (rawCodewordsOffset != rawCodewords.length) {\r
- throw new IllegalStateException();\r
- }\r
-\r
- return result;\r
- }\r
-\r
- int getNumDataCodewords() {\r
- return numDataCodewords;\r
- }\r
-\r
- byte[] getCodewords() {\r
- return codewords;\r
- }\r
-\r
-}\r
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.google.zxing.qrcode.decoder;\r
-\r
-/**\r
- * Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations\r
- * of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix,\r
- * including areas used for finder patterns, timing patterns, etc. These areas should be unused\r
- * after the point they are unmasked anyway.\r
- *\r
- * Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position\r
- * and j is row position. In fact, as the text says, i is row position and j is column position.\r
- *\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-abstract class DataMask {\r
-\r
- /**\r
- * See ISO 18004:2006 6.8.1\r
- */\r
- private static final DataMask[] DATA_MASKS = new DataMask[]{\r
- new DataMask000(),\r
- new DataMask001(),\r
- new DataMask010(),\r
- new DataMask011(),\r
- new DataMask100(),\r
- new DataMask101(),\r
- new DataMask110(),\r
- new DataMask111(),\r
- };\r
-\r
- private DataMask() {\r
- }\r
-\r
- abstract void unmaskBitMatrix(int[] bits, int dimension);\r
-\r
- static DataMask forReference(int reference) {\r
- if (reference < 0 || reference > 7) {\r
- throw new IllegalArgumentException();\r
- }\r
- return DATA_MASKS[reference];\r
- }\r
-\r
- /**\r
- * 000: mask bits for which (i + j) mod 2 == 0\r
- */\r
- private static class DataMask000 extends DataMask {\r
- private static final int BITMASK = 0x55555555; // = 010101...\r
-\r
- void unmaskBitMatrix(int[] bits, int dimension) {\r
- // This one's easy. Because the dimension of BitMatrix is always odd,\r
- // we can merely flip every other bit\r
- int max = bits.length;\r
- for (int i = 0; i < max; i++) {\r
- bits[i] ^= BITMASK;\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * 001: mask bits for which j mod 2 == 0\r
- */\r
- private static class DataMask001 extends DataMask {\r
- void unmaskBitMatrix(int[] bits, int dimension) {\r
- int bitMask = 0;\r
- int count = 0;\r
- int offset = 0;\r
- for (int j = 0; j < dimension; j++) {\r
- for (int i = 0; i < dimension; i++) {\r
- if ((i & 0x01) == 0) {\r
- bitMask |= 1 << count;\r
- }\r
- if (++count == 32) {\r
- bits[offset++] ^= bitMask;\r
- count = 0;\r
- bitMask = 0;\r
- }\r
- }\r
- }\r
- bits[offset] ^= bitMask;\r
- }\r
- }\r
-\r
- /**\r
- * 010: mask bits for which j mod 3 == 0\r
- */\r
- private static class DataMask010 extends DataMask {\r
- void unmaskBitMatrix(int[] bits, int dimension) {\r
- int bitMask = 0;\r
- int count = 0;\r
- int offset = 0;\r
- for (int j = 0; j < dimension; j++) {\r
- boolean columnMasked = j % 3 == 0;\r
- for (int i = 0; i < dimension; i++) {\r
- if (columnMasked) {\r
- bitMask |= 1 << count;\r
- }\r
- if (++count == 32) {\r
- bits[offset++] ^= bitMask;\r
- count = 0;\r
- bitMask = 0;\r
- }\r
- }\r
- }\r
- bits[offset] ^= bitMask;\r
- }\r
- }\r
-\r
- /**\r
- * 011: mask bits for which (i + j) mod 3 == 0\r
- */\r
- private static class DataMask011 extends DataMask {\r
- void unmaskBitMatrix(int[] bits, int dimension) {\r
- int bitMask = 0;\r
- int count = 0;\r
- int offset = 0;\r
- for (int j = 0; j < dimension; j++) {\r
- for (int i = 0; i < dimension; i++) {\r
- if ((i + j) % 3 == 0) {\r
- bitMask |= 1 << count;\r
- }\r
- if (++count == 32) {\r
- bits[offset++] ^= bitMask;\r
- count = 0;\r
- bitMask = 0;\r
- }\r
- }\r
- }\r
- bits[offset] ^= bitMask;\r
- }\r
- }\r
-\r
- /**\r
- * 100: mask bits for which (i/2 + j/3) mod 2 == 0\r
- */\r
- private static class DataMask100 extends DataMask {\r
- void unmaskBitMatrix(int[] bits, int dimension) {\r
- int bitMask = 0;\r
- int count = 0;\r
- int offset = 0;\r
- for (int j = 0; j < dimension; j++) {\r
- int jComponent = j / 3;\r
- for (int i = 0; i < dimension; i++) {\r
- if (((i >> 1 + jComponent) & 0x01) == 0) {\r
- bitMask |= 1 << count;\r
- }\r
- if (++count == 32) {\r
- bits[offset++] ^= bitMask;\r
- count = 0;\r
- bitMask = 0;\r
- }\r
- }\r
- }\r
- bits[offset] ^= bitMask;\r
- }\r
- }\r
-\r
- /**\r
- * 101: mask bits for which ij mod 2 + ij mod 3 == 0\r
- */\r
- private static class DataMask101 extends DataMask {\r
- void unmaskBitMatrix(int[] bits, int dimension) {\r
- int bitMask = 0;\r
- int count = 0;\r
- int offset = 0;\r
- for (int j = 0; j < dimension; j++) {\r
- for (int i = 0; i < dimension; i++) {\r
- int product = i * j;\r
- if (((product & 0x01) == 0) && product % 3 == 0) {\r
- bitMask |= 1 << count;\r
- }\r
- if (++count == 32) {\r
- bits[offset++] ^= bitMask;\r
- count = 0;\r
- bitMask = 0;\r
- }\r
- }\r
- }\r
- bits[offset] ^= bitMask;\r
- }\r
- }\r
-\r
- /**\r
- * 110: mask bits for which (ij mod 2 + ij mod 3) mod 2 == 0\r
- */\r
- private static class DataMask110 extends DataMask {\r
- void unmaskBitMatrix(int[] bits, int dimension) {\r
- int bitMask = 0;\r
- int count = 0;\r
- int offset = 0;\r
- for (int j = 0; j < dimension; j++) {\r
- for (int i = 0; i < dimension; i++) {\r
- int product = i * j;\r
- if ((((product & 0x01) + product % 3) & 0x01) == 0) {\r
- bitMask |= 1 << count;\r
- }\r
- if (++count == 32) {\r
- bits[offset++] ^= bitMask;\r
- count = 0;\r
- bitMask = 0;\r
- }\r
- }\r
- }\r
- bits[offset] ^= bitMask;\r
- }\r
- }\r
-\r
- /**\r
- * 111: mask bits for which ((i+j)mod 2 + ij mod 3) mod 2 == 0\r
- */\r
- private static class DataMask111 extends DataMask {\r
- void unmaskBitMatrix(int[] bits, int dimension) {\r
- int bitMask = 0;\r
- int count = 0;\r
- int offset = 0;\r
- for (int j = 0; j < dimension; j++) {\r
- for (int i = 0; i < dimension; i++) {\r
- if (((((i + j) & 0x01) + (i * j) % 3) & 0x01) == 0) {\r
- bitMask |= 1 << count;\r
- }\r
- if (++count == 32) {\r
- bits[offset++] ^= bitMask;\r
- count = 0;\r
- bitMask = 0;\r
- }\r
- }\r
- }\r
- bits[offset] ^= bitMask;\r
- }\r
- }\r
-}\r
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode.decoder;
-
-import com.google.zxing.ReaderException;
-
-import java.io.UnsupportedEncodingException;
-
-/**
- * See ISO 18004:2006, 6.4.3 - 6.4.7
- *
- * @author srowen@google.com (Sean Owen)
- */
-final class DecodedBitStreamParser {
-
- /**
- * See ISO 18004:2006, 6.4.4 Table 5
- */
- private static final char[] ALPHANUMERIC_CHARS = new char[]{
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
- 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
- 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- ' ', '$', '%', '*', '+', '-', '.', '/', ':'
- };
- private static final String SHIFT_JIS = "Shift_JIS";
- private static final boolean ASSUME_SHIFT_JIS;
-
- static {
- String platformDefault = System.getProperty("file.encoding");
- ASSUME_SHIFT_JIS = SHIFT_JIS.equalsIgnoreCase(platformDefault) ||
- "EUC-JP".equalsIgnoreCase(platformDefault);
- }
-
- private DecodedBitStreamParser() {
- }
-
- static String decode(byte[] bytes, Version version) throws ReaderException {
- BitSource bits = new BitSource(bytes);
- StringBuffer result = new StringBuffer();
- Mode mode;
- do {
- // While still another segment to read...
- mode = Mode.forBits(bits.readBits(4));
- if (!mode.equals(Mode.TERMINATOR)) {
- int count = bits.readBits(mode.getCharacterCountBits(version));
- if (mode.equals(Mode.NUMERIC)) {
- decodeNumericSegment(bits, result, count);
- } else if (mode.equals(Mode.ALPHANUMERIC)) {
- decodeAlphanumericSegment(bits, result, count);
- } else if (mode.equals(Mode.BYTE)) {
- decodeByteSegment(bits, result, count);
- } else if (mode.equals(Mode.KANJI)) {
- decodeKanjiSegment(bits, result, count);
- } else {
- throw new ReaderException("Unsupported mode indicator: " + mode);
- }
- }
- } while (!mode.equals(Mode.TERMINATOR));
-
- /*
- int bitsLeft = bits.available();
- if (bitsLeft > 0) {
- if (bitsLeft > 6 || bits.readBits(bitsLeft) != 0) {
- throw new ReaderException("Excess bits or non-zero bits after terminator mode indicator");
- }
- }
- */
- return result.toString();
- }
-
- private static void decodeKanjiSegment(BitSource bits,
- StringBuffer result,
- int count) throws ReaderException {
- byte[] buffer = new byte[2 * count];
- int offset = 0;
- while (count > 0) {
- int twoBytes = bits.readBits(13);
- int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0);
- if (assembledTwoBytes < 0x01F00) {
- // In the 0x8140 to 0x9FFC range
- assembledTwoBytes += 0x08140;
- } else {
- // In the 0xE040 to 0xEBBF range
- assembledTwoBytes += 0x0C140;
- }
- buffer[offset] = (byte) (assembledTwoBytes >> 8);
- buffer[offset + 1] = (byte) assembledTwoBytes;
- offset += 2;
- count--;
- }
- // Shift_JIS may not be supported in some environments:
- try {
- result.append(new String(buffer, "Shift_JIS"));
- } catch (UnsupportedEncodingException uee) {
- throw new ReaderException("Can't decode SHIFT_JIS string: " + uee);
- }
- }
-
- private static void decodeByteSegment(BitSource bits,
- StringBuffer result,
- int count) throws ReaderException {
- byte[] readBytes = new byte[count];
- if (count << 3 > bits.available()) {
- throw new ReaderException("Count too large: " + count);
- }
- for (int i = 0; i < count; i++) {
- readBytes[i] = (byte) bits.readBits(8);
- }
- // The spec isn't clear on this mode; see
- // section 6.4.5: t does not say which encoding to assuming
- // upon decoding. I have seen ISO-8859-1 used as well as
- // Shift_JIS -- without anything like an ECI designator to
- // give a hint.
- String encoding = guessEncoding(readBytes);
- try {
- result.append(new String(readBytes, encoding));
- } catch (UnsupportedEncodingException uce) {
- throw new ReaderException(uce.toString());
- }
- }
-
- private static void decodeAlphanumericSegment(BitSource bits,
- StringBuffer result,
- int count) {
- // Read two characters at a time
- while (count > 1) {
- int nextTwoCharsBits = bits.readBits(11);
- result.append(ALPHANUMERIC_CHARS[nextTwoCharsBits / 45]);
- result.append(ALPHANUMERIC_CHARS[nextTwoCharsBits % 45]);
- count -= 2;
- }
- if (count == 1) {
- // special case on char left
- result.append(ALPHANUMERIC_CHARS[bits.readBits(6)]);
- }
- }
-
- private static void decodeNumericSegment(BitSource bits,
- StringBuffer result,
- int count) throws ReaderException {
- while (count >= 3) {
- int threeDigitsBits = bits.readBits(10);
- if (threeDigitsBits >= 1000) {
- throw new ReaderException("Illegal value for 3-digit unit: " + threeDigitsBits);
- }
- result.append(ALPHANUMERIC_CHARS[threeDigitsBits / 100]);
- result.append(ALPHANUMERIC_CHARS[(threeDigitsBits / 10) % 10]);
- result.append(ALPHANUMERIC_CHARS[threeDigitsBits % 10]);
- count -= 3;
- }
- if (count == 2) {
- int twoDigitsBits = bits.readBits(7);
- if (twoDigitsBits >= 100) {
- throw new ReaderException("Illegal value for 2-digit unit: " + twoDigitsBits);
- }
- result.append(ALPHANUMERIC_CHARS[twoDigitsBits / 10]);
- result.append(ALPHANUMERIC_CHARS[twoDigitsBits % 10]);
- } else if (count == 1) {
- int digitBits = bits.readBits(4);
- if (digitBits >= 10) {
- throw new ReaderException("Illegal value for digit unit: " + digitBits);
- }
- result.append(ALPHANUMERIC_CHARS[digitBits]);
- }
- }
-
- private static String guessEncoding(byte[] bytes) {
- if (ASSUME_SHIFT_JIS) {
- return SHIFT_JIS;
- }
- // For now, merely tries to distinguish ISO-8859-1 and Shift_JIS,
- // which should be by far the most common encodings. ISO-8859-1
- // should not have bytes in the 0x80 - 0x9F range, while Shift_JIS
- // uses this as a first byte of a two-byte character. If we see this
- // followed by a valid second byte in Shift_JIS, assume it is Shift_JIS.
- int length = bytes.length;
- for (int i = 0; i < length; i++) {
- int value = bytes[i] & 0xFF;
- if (value >= 0x80 && value <= 0x9F && i < length - 1) {
- // ISO-8859-1 shouldn't use this, but before we decide it is Shift_JIS,
- // just double check that it is followed by a byte that's valid in
- // the Shift_JIS encoding
- int nextValue = bytes[i + 1] & 0xFF;
- if ((value & 0x1) == 0) {
- // if even,
- if (nextValue >= 0x40 && nextValue <= 0x9E) {
- return SHIFT_JIS;
- }
- } else {
- if (nextValue >= 0x9F && nextValue <= 0x7C) {
- return SHIFT_JIS;
- }
- }
- }
- }
- return "ISO-8859-1";
- }
-
-}
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.google.zxing.qrcode.decoder;\r
-\r
-import com.google.zxing.ReaderException;\r
-import com.google.zxing.common.BitMatrix;\r
-import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;\r
-import com.google.zxing.common.reedsolomon.ReedSolomonException;\r
-\r
-/**\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-public final class Decoder {\r
-\r
- private Decoder() {\r
- }\r
-\r
- public static String decode(boolean[][] image) throws ReaderException {\r
- int dimension = image.length;\r
- BitMatrix bits = new BitMatrix(dimension);\r
- for (int i = 0; i < dimension; i++) {\r
- for (int j = 0; j < dimension; j++) {\r
- if (image[i][j]) {\r
- bits.set(i, j);\r
- }\r
- }\r
- }\r
- return decode(bits);\r
- }\r
-\r
- public static String decode(BitMatrix bits) throws ReaderException {\r
- BitMatrixParser parser = new BitMatrixParser(bits);\r
- Version version = parser.readVersion();\r
- ErrorCorrectionLevel ecLevel = parser.readFormatInformation().getErrorCorrectionLevel();\r
- byte[] codewords = parser.readCodewords();\r
- DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel);\r
- int totalBytes = 0;\r
- for (int i = 0; i < dataBlocks.length; i++) {\r
- totalBytes += dataBlocks[i].getNumDataCodewords();\r
- }\r
- byte[] resultBytes = new byte[totalBytes];\r
- int resultOffset = 0;\r
- for (int j = 0; j < dataBlocks.length; j++) {\r
- DataBlock dataBlock = dataBlocks[j];\r
- byte[] codewordBytes = dataBlock.getCodewords();\r
- int numDataCodewords = dataBlock.getNumDataCodewords();\r
- correctErrors(codewordBytes, numDataCodewords);\r
- for (int i = 0; i < numDataCodewords; i++) {\r
- resultBytes[resultOffset++] = codewordBytes[i];\r
- }\r
- }\r
-\r
- return DecodedBitStreamParser.decode(resultBytes, version);\r
- }\r
-\r
- private static void correctErrors(byte[] codewordBytes, int numDataCodewords)\r
- throws ReaderException {\r
- int numCodewords = codewordBytes.length;\r
- int[] codewordsInts = new int[numCodewords];\r
- for (int i = 0; i < numCodewords; i++) {\r
- codewordsInts[i] = codewordBytes[i] & 0xFF;\r
- }\r
- int numECCodewords = codewordBytes.length - numDataCodewords;\r
- try {\r
- ReedSolomonDecoder.decode(codewordsInts, numECCodewords);\r
- } catch (ReedSolomonException rse) {\r
- throw new ReaderException(rse.toString());\r
- }\r
- for (int i = 0; i < numDataCodewords; i++) {\r
- codewordBytes[i] = (byte) codewordsInts[i];\r
- }\r
- }\r
-\r
-}\r
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode.decoder;
-
-/**
- * <p>See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels
- * defined by the QR code standard.</p>
- *
- * @author srowen@google.com (Sean Owen)
- */
-final class ErrorCorrectionLevel {
-
- // No, we can't use an enum here. J2ME doesn't support it.
-
- /** L = ~7% correction */
- static final ErrorCorrectionLevel L = new ErrorCorrectionLevel(0);
- /** M = ~15% correction */
- static final ErrorCorrectionLevel M = new ErrorCorrectionLevel(1);
- /** Q = ~25% correction */
- static final ErrorCorrectionLevel Q = new ErrorCorrectionLevel(2);
- /** H = ~30% correction */
- static final ErrorCorrectionLevel H = new ErrorCorrectionLevel(3);
-
- private static final ErrorCorrectionLevel[] FOR_BITS = new ErrorCorrectionLevel[] { M, L, H, Q };
-
- private final int ordinal;
-
- private ErrorCorrectionLevel(final int ordinal) {
- this.ordinal = ordinal;
- }
-
- int ordinal() {
- return ordinal;
- }
-
- static ErrorCorrectionLevel forBits(int bits) {
- return FOR_BITS[bits];
- }
-
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode.decoder;
-
-/**
- * @author srowen@google.com (Sean Owen)
- */
-final class FormatInformation {
-
- private static final int FORMAT_INFO_MASK_QR = 0x5412;
-
- /**
- * See ISO 18004:2006, Annex C, Table C.1
- */
- private static final int[][] FORMAT_INFO_DECODE_LOOKUP = new int[][]{
- {0x5412, 0x00},
- {0x5125, 0x01},
- {0x5E7C, 0x02},
- {0x5B4B, 0x03},
- {0x45F9, 0x04},
- {0x40CE, 0x05},
- {0x4F97, 0x06},
- {0x4AA0, 0x07},
- {0x77C4, 0x08},
- {0x72F3, 0x09},
- {0x7DAA, 0x0A},
- {0x789D, 0x0B},
- {0x662F, 0x0C},
- {0x6318, 0x0D},
- {0x6C41, 0x0E},
- {0x6976, 0x0F},
- {0x1689, 0x10},
- {0x13BE, 0x11},
- {0x1CE7, 0x12},
- {0x19D0, 0x13},
- {0x0762, 0x14},
- {0x0255, 0x15},
- {0x0D0C, 0x16},
- {0x083B, 0x17},
- {0x355F, 0x18},
- {0x3068, 0x19},
- {0x3F31, 0x1A},
- {0x3A06, 0x1B},
- {0x24B4, 0x1C},
- {0x2183, 0x1D},
- {0x2EDA, 0x1E},
- {0x2BED, 0x1F},
- };
-
- private static final int[] BITS_SET_IN_HALF_BYTE =
- new int[]{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
-
- private final ErrorCorrectionLevel errorCorrectionLevel;
- private final byte dataMask;
-
- private FormatInformation(int formatInfo) {
- // Bits 3,4
- errorCorrectionLevel =
- ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03);
- // Bottom 3 bits
- dataMask = (byte) (formatInfo & 0x07);
- }
-
- static int numBitsDiffering(int a, int b) {
- a ^= b;
- return
- BITS_SET_IN_HALF_BYTE[a & 0x0F] +
- BITS_SET_IN_HALF_BYTE[(a >>> 4 & 0x0F)] +
- BITS_SET_IN_HALF_BYTE[(a >>> 8 & 0x0F)] +
- BITS_SET_IN_HALF_BYTE[(a >>> 12 & 0x0F)] +
- BITS_SET_IN_HALF_BYTE[(a >>> 16 & 0x0F)] +
- BITS_SET_IN_HALF_BYTE[(a >>> 20 & 0x0F)] +
- BITS_SET_IN_HALF_BYTE[(a >>> 24 & 0x0F)] +
- BITS_SET_IN_HALF_BYTE[(a >>> 28 & 0x0F)];
- }
-
- static FormatInformation decodeFormatInformation(int rawFormatInfo) {
- FormatInformation formatInfo = doDecodeFormatInformation(rawFormatInfo);
- if (formatInfo != null) {
- return formatInfo;
- }
- // Should return null, but, some QR codes apparently
- // do not mask this info. Try again, first masking the raw bits so
- // the function will unmask
- return doDecodeFormatInformation(rawFormatInfo ^ FORMAT_INFO_MASK_QR);
- }
-
- private static FormatInformation doDecodeFormatInformation(
- int rawFormatInfo) {
- // Unmask:
- int unmaskedFormatInfo = rawFormatInfo ^ FORMAT_INFO_MASK_QR;
- int bestDifference = Integer.MAX_VALUE;
- int bestFormatInfo = 0;
- for (int i = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++) {
- int[] decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i];
- int targetInfo = decodeInfo[0];
- if (targetInfo == unmaskedFormatInfo) {
- return new FormatInformation(decodeInfo[1]);
- }
- int bitsDifference = numBitsDiffering(unmaskedFormatInfo, targetInfo);
- if (bitsDifference < bestDifference) {
- bestFormatInfo = decodeInfo[1];
- bestDifference = bitsDifference;
- }
- }
- if (bestDifference <= 3) {
- return new FormatInformation(bestFormatInfo);
- }
- return null;
- }
-
- ErrorCorrectionLevel getErrorCorrectionLevel() {
- return errorCorrectionLevel;
- }
-
- byte getDataMask() {
- return dataMask;
- }
-
- public int hashCode() {
- return (errorCorrectionLevel.ordinal() << 3) | (int) dataMask;
- }
-
- public boolean equals(Object o) {
- if (!(o instanceof FormatInformation)) {
- return false;
- }
- FormatInformation other = (FormatInformation) o;
- return this.errorCorrectionLevel == other.errorCorrectionLevel &&
- this.dataMask == other.dataMask;
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode.decoder;
-
-import com.google.zxing.ReaderException;
-
-/**
- * <p>See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which
- * data can be encoded to bits in the QR code standard.</p>
- *
- * @author srowen@google.com (Sean Owen)
- */
-final class Mode {
-
- // No, we can't use an enum here. J2ME doesn't support it.
-
- static final Mode TERMINATOR = new Mode(new int[] {0, 0, 0}); // Not really a mode...
- static final Mode NUMERIC = new Mode(new int[] {10, 12, 14});
- static final Mode ALPHANUMERIC = new Mode(new int[] {9, 11, 13});
- static final Mode BYTE = new Mode(new int[] {8, 16, 16});
- static final Mode KANJI = new Mode(new int[] {8, 10, 12});
-
- private int[] characterCountBitsForVersions;
-
- private Mode(int[] characterCountBitsForVersions) {
- this.characterCountBitsForVersions = characterCountBitsForVersions;
- }
-
- static Mode forBits(int bits) throws ReaderException {
- switch (bits) {
- case 0x0:
- return TERMINATOR;
- case 0x1:
- return NUMERIC;
- case 0x2:
- return ALPHANUMERIC;
- case 0x4:
- return BYTE;
- case 0x8:
- return KANJI;
- default:
- throw new ReaderException("Illegal mode bits: " + bits);
- }
- }
-
- int getCharacterCountBits(Version version) {
- int number = version.getVersionNumber();
- int offset;
- if (number <= 9) {
- offset = 0;
- } else if (number <= 26) {
- offset = 1;
- } else {
- offset = 2;
- }
- return characterCountBitsForVersions[offset];
- }
-
-}
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.google.zxing.qrcode.decoder;\r
-\r
-import com.google.zxing.ReaderException;\r
-import com.google.zxing.common.BitMatrix;\r
-\r
-/**\r
- * See ISO 18004:2006 Annex D\r
- *\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-public final class Version {\r
-\r
- /**\r
- * See ISO 18004:2006 Annex D.\r
- * Element i represents the raw version bits that specify version i + 7\r
- */\r
- private static final int[] VERSION_DECODE_INFO = new int[]{\r
- 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6,\r
- 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78,\r
- 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683,\r
- 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,\r
- 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250,\r
- 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B,\r
- 0x2542E, 0x26A64, 0x27541, 0x28C69\r
- };\r
-\r
- private static final Version[] VERSIONS = buildVersions();\r
-\r
- private final int versionNumber;\r
- private final int[] alignmentPatternCenters;\r
- private final ECBlocks[] ecBlocks;\r
- private final int totalCodewords;\r
-\r
- private Version(int versionNumber,\r
- int[] alignmentPatternCenters,\r
- ECBlocks ecBlocks1,\r
- ECBlocks ecBlocks2,\r
- ECBlocks ecBlocks3,\r
- ECBlocks ecBlocks4) {\r
- this.versionNumber = versionNumber;\r
- this.alignmentPatternCenters = alignmentPatternCenters;\r
- this.ecBlocks = new ECBlocks[] { ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4 };\r
- int total = 0;\r
- ECBlocks levelLECBlocks = ecBlocks1; // L,M,Q,H -- all the same total\r
- int ecCodewords = levelLECBlocks.ecCodewords;\r
- ECB[] ecbArray = levelLECBlocks.ecBlocks;\r
- for (int i = 0; i < ecbArray.length; i++) {\r
- ECB ecBlock = ecbArray[i];\r
- total += ecBlock.count * (ecBlock.dataCodewords + ecCodewords);\r
- }\r
- this.totalCodewords = total;\r
- }\r
-\r
- public int getVersionNumber() {\r
- return versionNumber;\r
- }\r
-\r
- public int[] getAlignmentPatternCenters() {\r
- return alignmentPatternCenters;\r
- }\r
-\r
- public int getTotalCodewords() {\r
- return totalCodewords;\r
- }\r
-\r
- public int getDimensionForVersion() {\r
- return 17 + 4 * versionNumber;\r
- }\r
-\r
- ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) {\r
- return ecBlocks[ecLevel.ordinal()];\r
- }\r
-\r
- public static Version getProvisionalVersionForDimension(int dimension)\r
- throws ReaderException {\r
- if (dimension % 4 != 1) {\r
- throw new ReaderException("Dimension must be 1 mod 4");\r
- }\r
- return getVersionForNumber((dimension - 17) >> 2);\r
- }\r
-\r
- public static Version getVersionForNumber(int versionNumber)\r
- throws ReaderException {\r
- if (versionNumber < 1 || versionNumber > 40) {\r
- throw new ReaderException(\r
- "versionNumber must be between 1 and 40");\r
- }\r
- return VERSIONS[versionNumber - 1];\r
- }\r
-\r
- static Version decodeVersionInformation(int versionBits)\r
- throws ReaderException {\r
- int bestDifference = Integer.MAX_VALUE;\r
- int bestVersion = 0;\r
- for (int i = 0; i < VERSION_DECODE_INFO.length; i++) {\r
- int targetVersion = VERSION_DECODE_INFO[i];\r
- if (targetVersion == versionBits) {\r
- return getVersionForNumber(i + 7);\r
- }\r
- int bitsDifference =\r
- FormatInformation.numBitsDiffering(versionBits, targetVersion);\r
- if (bitsDifference < bestDifference) {\r
- bestVersion = i + 7;\r
- }\r
- }\r
- if (bestDifference <= 3) {\r
- return getVersionForNumber(bestVersion);\r
- }\r
- return null;\r
- }\r
-\r
- /**\r
- * See ISO 18004:2006 Annex E\r
- */\r
- BitMatrix buildFunctionPattern() {\r
- int dimension = getDimensionForVersion();\r
- BitMatrix bitMatrix = new BitMatrix(dimension);\r
-\r
- // Top left finder pattern + separator + format\r
- bitMatrix.setRegion(0, 0, 9, 9);\r
- // Top right finder pattern + separator + format\r
- bitMatrix.setRegion(0, dimension - 8, 9, 8);\r
- // Bottom left finder pattern + separator + format\r
- bitMatrix.setRegion(dimension - 8, 0, 8, 9);\r
-\r
- // Alignment patterns\r
- int max = alignmentPatternCenters.length;\r
- for (int x = 0; x < max; x++) {\r
- int i = alignmentPatternCenters[x] - 2;\r
- for (int y = 0; y < max; y++) {\r
- if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) {\r
- // No alignment patterns near the three finder paterns\r
- continue;\r
- }\r
- bitMatrix.setRegion(i, alignmentPatternCenters[y] - 2, 5, 5);\r
- }\r
- }\r
-\r
- // Vertical timing pattern\r
- bitMatrix.setRegion(9, 6, dimension - 17, 1);\r
- // Horizontal timing pattern\r
- bitMatrix.setRegion(6, 9, 1, dimension - 17);\r
-\r
- if (versionNumber > 6) {\r
- // Version info, top right\r
- bitMatrix.setRegion(0, dimension - 11, 6, 3);\r
- // Version info, bottom left\r
- bitMatrix.setRegion(dimension - 11, 0, 3, 6);\r
- }\r
-\r
- return bitMatrix;\r
- }\r
-\r
- /**\r
- * <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will\r
- * use blocks of differing sizes within one version, so, this encapsulates the parameters for\r
- * each set of blocks. It also holds the number of error-correction codewords per block since it\r
- * will be the same across all blocks within one version.</p>\r
- */\r
- static final class ECBlocks {\r
- private int ecCodewords;\r
- private ECB[] ecBlocks;\r
-\r
- private ECBlocks(int ecCodewords, ECB ecBlocks) {\r
- this.ecCodewords = ecCodewords;\r
- this.ecBlocks = new ECB[] { ecBlocks };\r
- }\r
-\r
- private ECBlocks(int ecCodewords, ECB ecBlocks1, ECB ecBlocks2) {\r
- this.ecCodewords = ecCodewords;\r
- this.ecBlocks = new ECB[] { ecBlocks1, ecBlocks2 };\r
- }\r
-\r
- int getECCodewords() {\r
- return ecCodewords;\r
- }\r
-\r
- ECB[] getECBlocks() {\r
- return ecBlocks;\r
- }\r
- }\r
-\r
- /**\r
- * <p>Encapsualtes the parameters for one error-correction block in one symbol version.\r
- * This includes the number of data codewords, and the number of times a block with these\r
- * parameters is used consecutively in the QR code version's format.</p>\r
- */\r
- static final class ECB {\r
- private int count;\r
- private int dataCodewords;\r
-\r
- private ECB(int count, int dataCodewords) {\r
- this.count = count;\r
- this.dataCodewords = dataCodewords;\r
- }\r
-\r
- int getCount() {\r
- return count;\r
- }\r
-\r
- int getDataCodewords() {\r
- return dataCodewords;\r
- }\r
- }\r
-\r
- public String toString() {\r
- return String.valueOf(versionNumber);\r
- }\r
-\r
- /**\r
- * See ISO 18004:2006 6.5.1 Table 9\r
- */\r
- private static Version[] buildVersions() {\r
- return new Version[]{\r
- new Version(1, new int[]{},\r
- new ECBlocks(7, new ECB(1, 19)),\r
- new ECBlocks(10, new ECB(1, 16)),\r
- new ECBlocks(13, new ECB(1, 13)),\r
- new ECBlocks(17, new ECB(1, 9))),\r
- new Version(2, new int[]{6, 18},\r
- new ECBlocks(10, new ECB(1, 34)),\r
- new ECBlocks(16, new ECB(1, 28)),\r
- new ECBlocks(22, new ECB(1, 22)),\r
- new ECBlocks(28, new ECB(1, 16))),\r
- new Version(3, new int[]{6, 22},\r
- new ECBlocks(15, new ECB(1, 55)),\r
- new ECBlocks(26, new ECB(1, 44)),\r
- new ECBlocks(18, new ECB(2, 17)),\r
- new ECBlocks(22, new ECB(2, 13))),\r
- new Version(4, new int[]{6, 26},\r
- new ECBlocks(20, new ECB(1, 80)),\r
- new ECBlocks(18, new ECB(2, 32)),\r
- new ECBlocks(26, new ECB(2, 24)),\r
- new ECBlocks(16, new ECB(4, 9))),\r
- new Version(5, new int[]{6, 30},\r
- new ECBlocks(26, new ECB(1, 108)),\r
- new ECBlocks(24, new ECB(2, 43)),\r
- new ECBlocks(18, new ECB(2, 15),\r
- new ECB(2, 16)),\r
- new ECBlocks(22, new ECB(2, 11),\r
- new ECB(2, 12))),\r
- new Version(6, new int[]{6, 34},\r
- new ECBlocks(18, new ECB(2, 68)),\r
- new ECBlocks(16, new ECB(4, 27)),\r
- new ECBlocks(24, new ECB(4, 19)),\r
- new ECBlocks(28, new ECB(4, 15))),\r
- new Version(7, new int[]{6, 22, 38},\r
- new ECBlocks(20, new ECB(2, 78)),\r
- new ECBlocks(18, new ECB(4, 31)),\r
- new ECBlocks(18, new ECB(2, 14),\r
- new ECB(4, 15)),\r
- new ECBlocks(26, new ECB(4, 13),\r
- new ECB(1, 14))),\r
- new Version(8, new int[]{6, 24, 42},\r
- new ECBlocks(24, new ECB(2, 97)),\r
- new ECBlocks(22, new ECB(2, 38),\r
- new ECB(2, 39)),\r
- new ECBlocks(22, new ECB(4, 18),\r
- new ECB(2, 19)),\r
- new ECBlocks(26, new ECB(4, 14),\r
- new ECB(2, 15))),\r
- new Version(9, new int[]{6, 26, 46},\r
- new ECBlocks(30, new ECB(2, 116)),\r
- new ECBlocks(22, new ECB(3, 36),\r
- new ECB(2, 37)),\r
- new ECBlocks(20, new ECB(4, 16),\r
- new ECB(4, 17)),\r
- new ECBlocks(24, new ECB(4, 12),\r
- new ECB(4, 13))),\r
- new Version(10, new int[]{6, 28, 50},\r
- new ECBlocks(18, new ECB(2, 68),\r
- new ECB(2, 69)),\r
- new ECBlocks(26, new ECB(4, 43),\r
- new ECB(1, 44)),\r
- new ECBlocks(24, new ECB(6, 19),\r
- new ECB(2, 20)),\r
- new ECBlocks(28, new ECB(6, 15),\r
- new ECB(2, 16))),\r
- new Version(11, new int[]{6, 30, 54},\r
- new ECBlocks(20, new ECB(4, 81)),\r
- new ECBlocks(30, new ECB(1, 50),\r
- new ECB(4, 51)),\r
- new ECBlocks(28, new ECB(4, 22),\r
- new ECB(4, 23)),\r
- new ECBlocks(24, new ECB(3, 12),\r
- new ECB(8, 13))),\r
- new Version(12, new int[]{6, 32, 58},\r
- new ECBlocks(24, new ECB(2, 92),\r
- new ECB(2, 93)),\r
- new ECBlocks(22, new ECB(6, 36),\r
- new ECB(2, 37)),\r
- new ECBlocks(26, new ECB(4, 20),\r
- new ECB(6, 21)),\r
- new ECBlocks(28, new ECB(7, 14),\r
- new ECB(4, 15))),\r
- new Version(13, new int[]{6, 34, 62},\r
- new ECBlocks(26, new ECB(4, 107)),\r
- new ECBlocks(22, new ECB(8, 37),\r
- new ECB(1, 38)),\r
- new ECBlocks(24, new ECB(8, 20),\r
- new ECB(4, 21)),\r
- new ECBlocks(22, new ECB(12, 11),\r
- new ECB(4, 12))),\r
- new Version(14, new int[]{6, 26, 46, 66},\r
- new ECBlocks(30, new ECB(3, 115),\r
- new ECB(1, 116)),\r
- new ECBlocks(24, new ECB(4, 40),\r
- new ECB(5, 41)),\r
- new ECBlocks(20, new ECB(11, 16),\r
- new ECB(5, 17)),\r
- new ECBlocks(24, new ECB(11, 12),\r
- new ECB(5, 13))),\r
- new Version(15, new int[]{6, 26, 48, 70},\r
- new ECBlocks(22, new ECB(5, 87),\r
- new ECB(1, 88)),\r
- new ECBlocks(24, new ECB(5, 41),\r
- new ECB(5, 42)),\r
- new ECBlocks(30, new ECB(5, 24),\r
- new ECB(7, 25)),\r
- new ECBlocks(24, new ECB(11, 12),\r
- new ECB(7, 13))),\r
- new Version(16, new int[]{6, 26, 50, 74},\r
- new ECBlocks(24, new ECB(5, 98),\r
- new ECB(1, 99)),\r
- new ECBlocks(28, new ECB(7, 45),\r
- new ECB(3, 46)),\r
- new ECBlocks(24, new ECB(15, 19),\r
- new ECB(2, 20)),\r
- new ECBlocks(30, new ECB(3, 15),\r
- new ECB(13, 16))),\r
- new Version(17, new int[]{6, 30, 54, 78},\r
- new ECBlocks(28, new ECB(1, 107),\r
- new ECB(5, 108)),\r
- new ECBlocks(28, new ECB(10, 46),\r
- new ECB(1, 47)),\r
- new ECBlocks(28, new ECB(1, 22),\r
- new ECB(15, 23)),\r
- new ECBlocks(28, new ECB(2, 14),\r
- new ECB(17, 15))),\r
- new Version(18, new int[]{6, 30, 56, 82},\r
- new ECBlocks(30, new ECB(5, 120),\r
- new ECB(1, 121)),\r
- new ECBlocks(26, new ECB(9, 43),\r
- new ECB(4, 44)),\r
- new ECBlocks(28, new ECB(17, 22),\r
- new ECB(1, 23)),\r
- new ECBlocks(28, new ECB(2, 14),\r
- new ECB(19, 15))),\r
- new Version(19, new int[]{6, 30, 58, 86},\r
- new ECBlocks(28, new ECB(3, 113),\r
- new ECB(4, 114)),\r
- new ECBlocks(26, new ECB(3, 44),\r
- new ECB(11, 45)),\r
- new ECBlocks(26, new ECB(17, 21),\r
- new ECB(4, 22)),\r
- new ECBlocks(26, new ECB(9, 13),\r
- new ECB(16, 14))),\r
- new Version(20, new int[]{6, 34, 62, 90},\r
- new ECBlocks(28, new ECB(3, 107),\r
- new ECB(5, 108)),\r
- new ECBlocks(26, new ECB(3, 41),\r
- new ECB(13, 42)),\r
- new ECBlocks(30, new ECB(15, 24),\r
- new ECB(5, 25)),\r
- new ECBlocks(28, new ECB(15, 15),\r
- new ECB(10, 16))),\r
- new Version(21, new int[]{6, 28, 50, 72, 94},\r
- new ECBlocks(28, new ECB(4, 116),\r
- new ECB(4, 117)),\r
- new ECBlocks(26, new ECB(17, 42)),\r
- new ECBlocks(28, new ECB(17, 22),\r
- new ECB(6, 23)),\r
- new ECBlocks(30, new ECB(19, 16),\r
- new ECB(6, 17))),\r
- new Version(22, new int[]{6, 26, 50, 74, 98},\r
- new ECBlocks(28, new ECB(2, 111),\r
- new ECB(7, 112)),\r
- new ECBlocks(28, new ECB(17, 46)),\r
- new ECBlocks(30, new ECB(7, 24),\r
- new ECB(16, 25)),\r
- new ECBlocks(24, new ECB(34, 13))),\r
- new Version(23, new int[]{6, 30, 54, 74, 102},\r
- new ECBlocks(30, new ECB(4, 121),\r
- new ECB(5, 122)),\r
- new ECBlocks(28, new ECB(4, 47),\r
- new ECB(14, 48)),\r
- new ECBlocks(30, new ECB(11, 24),\r
- new ECB(14, 25)),\r
- new ECBlocks(30, new ECB(16, 15),\r
- new ECB(14, 16))),\r
- new Version(24, new int[]{6, 28, 54, 80, 106},\r
- new ECBlocks(30, new ECB(6, 117),\r
- new ECB(4, 118)),\r
- new ECBlocks(28, new ECB(6, 45),\r
- new ECB(14, 46)),\r
- new ECBlocks(30, new ECB(11, 24),\r
- new ECB(16, 25)),\r
- new ECBlocks(30, new ECB(30, 16),\r
- new ECB(2, 17))),\r
- new Version(25, new int[]{6, 32, 58, 84, 110},\r
- new ECBlocks(26, new ECB(8, 1061),\r
- new ECB(4, 107)),\r
- new ECBlocks(28, new ECB(8, 47),\r
- new ECB(13, 48)),\r
- new ECBlocks(30, new ECB(7, 24),\r
- new ECB(22, 25)),\r
- new ECBlocks(30, new ECB(22, 15),\r
- new ECB(13, 16))),\r
- new Version(26, new int[]{6, 30, 58, 86, 114},\r
- new ECBlocks(28, new ECB(10, 114),\r
- new ECB(2, 115)),\r
- new ECBlocks(28, new ECB(19, 46),\r
- new ECB(4, 47)),\r
- new ECBlocks(28, new ECB(28, 22),\r
- new ECB(6, 23)),\r
- new ECBlocks(30, new ECB(33, 16),\r
- new ECB(4, 17))),\r
- new Version(27, new int[]{6, 34, 62, 90, 118},\r
- new ECBlocks(30, new ECB(8, 122),\r
- new ECB(4, 123)),\r
- new ECBlocks(28, new ECB(22, 45),\r
- new ECB(3, 46)),\r
- new ECBlocks(30, new ECB(8, 23),\r
- new ECB(26, 24)),\r
- new ECBlocks(30, new ECB(12, 15),\r
- new ECB(28, 16))),\r
- new Version(28, new int[]{6, 26, 50, 74, 98, 122},\r
- new ECBlocks(30, new ECB(3, 117),\r
- new ECB(10, 118)),\r
- new ECBlocks(28, new ECB(3, 45),\r
- new ECB(23, 46)),\r
- new ECBlocks(30, new ECB(4, 24),\r
- new ECB(31, 25)),\r
- new ECBlocks(30, new ECB(11, 15),\r
- new ECB(31, 16))),\r
- new Version(29, new int[]{6, 30, 54, 78, 102, 126},\r
- new ECBlocks(30, new ECB(7, 116),\r
- new ECB(7, 117)),\r
- new ECBlocks(28, new ECB(21, 45),\r
- new ECB(7, 46)),\r
- new ECBlocks(30, new ECB(1, 23),\r
- new ECB(37, 24)),\r
- new ECBlocks(30, new ECB(19, 15),\r
- new ECB(26, 16))),\r
- new Version(30, new int[]{6, 26, 52, 78, 104, 130},\r
- new ECBlocks(30, new ECB(5, 115),\r
- new ECB(10, 116)),\r
- new ECBlocks(28, new ECB(19, 47),\r
- new ECB(10, 48)),\r
- new ECBlocks(30, new ECB(15, 24),\r
- new ECB(25, 25)),\r
- new ECBlocks(30, new ECB(23, 15),\r
- new ECB(25, 16))),\r
- new Version(31, new int[]{6, 30, 56, 82, 108, 134},\r
- new ECBlocks(30, new ECB(13, 115),\r
- new ECB(3, 116)),\r
- new ECBlocks(28, new ECB(2, 46),\r
- new ECB(29, 47)),\r
- new ECBlocks(30, new ECB(42, 24),\r
- new ECB(1, 25)),\r
- new ECBlocks(30, new ECB(23, 15),\r
- new ECB(28, 16))),\r
- new Version(32, new int[]{6, 34, 60, 86, 112, 138},\r
- new ECBlocks(30, new ECB(17, 115)),\r
- new ECBlocks(28, new ECB(10, 46),\r
- new ECB(23, 47)),\r
- new ECBlocks(30, new ECB(10, 24),\r
- new ECB(35, 25)),\r
- new ECBlocks(30, new ECB(19, 15),\r
- new ECB(35, 16))),\r
- new Version(33, new int[]{6, 30, 58, 86, 114, 142},\r
- new ECBlocks(30, new ECB(17, 115),\r
- new ECB(1, 116)),\r
- new ECBlocks(28, new ECB(14, 46),\r
- new ECB(21, 47)),\r
- new ECBlocks(30, new ECB(29, 24),\r
- new ECB(19, 25)),\r
- new ECBlocks(30, new ECB(11, 15),\r
- new ECB(46, 16))),\r
- new Version(34, new int[]{6, 34, 62, 90, 118, 146},\r
- new ECBlocks(30, new ECB(13, 115),\r
- new ECB(6, 116)),\r
- new ECBlocks(28, new ECB(14, 46),\r
- new ECB(23, 47)),\r
- new ECBlocks(30, new ECB(44, 24),\r
- new ECB(7, 25)),\r
- new ECBlocks(30, new ECB(59, 16),\r
- new ECB(1, 17))),\r
- new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150},\r
- new ECBlocks(30, new ECB(12, 121),\r
- new ECB(7, 122)),\r
- new ECBlocks(28, new ECB(12, 47),\r
- new ECB(26, 48)),\r
- new ECBlocks(30, new ECB(39, 24),\r
- new ECB(14, 25)),\r
- new ECBlocks(30, new ECB(22, 15),\r
- new ECB(41, 16))),\r
- new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154},\r
- new ECBlocks(30, new ECB(6, 121),\r
- new ECB(14, 122)),\r
- new ECBlocks(28, new ECB(6, 47),\r
- new ECB(34, 48)),\r
- new ECBlocks(30, new ECB(46, 24),\r
- new ECB(10, 25)),\r
- new ECBlocks(30, new ECB(2, 15),\r
- new ECB(64, 16))),\r
- new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158},\r
- new ECBlocks(30, new ECB(17, 122),\r
- new ECB(4, 123)),\r
- new ECBlocks(28, new ECB(29, 46),\r
- new ECB(14, 47)),\r
- new ECBlocks(30, new ECB(49, 24),\r
- new ECB(10, 25)),\r
- new ECBlocks(30, new ECB(24, 15),\r
- new ECB(46, 16))),\r
- new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162},\r
- new ECBlocks(30, new ECB(4, 122),\r
- new ECB(18, 123)),\r
- new ECBlocks(28, new ECB(13, 46),\r
- new ECB(32, 47)),\r
- new ECBlocks(30, new ECB(48, 24),\r
- new ECB(14, 25)),\r
- new ECBlocks(30, new ECB(42, 15),\r
- new ECB(32, 16))),\r
- new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166},\r
- new ECBlocks(30, new ECB(20, 117),\r
- new ECB(4, 118)),\r
- new ECBlocks(28, new ECB(40, 47),\r
- new ECB(7, 48)),\r
- new ECBlocks(30, new ECB(43, 24),\r
- new ECB(22, 25)),\r
- new ECBlocks(30, new ECB(10, 15),\r
- new ECB(67, 16))),\r
- new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170},\r
- new ECBlocks(30, new ECB(19, 118),\r
- new ECB(6, 119)),\r
- new ECBlocks(28, new ECB(18, 47),\r
- new ECB(31, 48)),\r
- new ECBlocks(30, new ECB(34, 24),\r
- new ECB(34, 25)),\r
- new ECBlocks(30, new ECB(20, 15),\r
- new ECB(61, 16)))\r
- };\r
- }\r
-\r
-}\r
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode.detector;
-
-import com.google.zxing.ResultPoint;
-
-/**
- * @author srowen@google.com (Sean Owen)
- */
-public final class AlignmentPattern implements ResultPoint {
-
- private final float posX;
- private final float posY;
- private final float estimatedModuleSize;
-
- AlignmentPattern(float posX, float posY, float estimatedModuleSize) {
- this.posX = posX;
- this.posY = posY;
- this.estimatedModuleSize = estimatedModuleSize;
- }
-
- public float getX() {
- return posX;
- }
-
- public float getY() {
- return posY;
- }
-
- float getEstimatedModuleSize() {
- return estimatedModuleSize;
- }
-
- boolean aboutEquals(float moduleSize, float i, float j) {
- return
- Math.abs(i - posY) <= moduleSize &&
- Math.abs(j - posX) <= moduleSize &&
- (Math.abs(moduleSize - estimatedModuleSize) <= 1.0f ||
- Math.abs(moduleSize - estimatedModuleSize) / estimatedModuleSize <= 0.1f);
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.google.zxing.qrcode.detector;\r
-\r
-import com.google.zxing.MonochromeBitmapSource;\r
-import com.google.zxing.ReaderException;\r
-import com.google.zxing.common.BitArray;\r
-\r
-import java.util.Vector;\r
-\r
-/**\r
- * <p>At the moment this only looks for the bottom-right alignment pattern.</p>\r
- *\r
- * <p>This class is not thread-safe.</p>\r
- *\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-final class AlignmentPatternFinder {\r
-\r
- private final MonochromeBitmapSource image;\r
- private final Vector possibleCenters;\r
- private final int startX;\r
- private final int startY;\r
- private final int width;\r
- private final int height;\r
- private final float moduleSize;\r
-\r
- AlignmentPatternFinder(MonochromeBitmapSource image,\r
- int startX,\r
- int startY,\r
- int width,\r
- int height,\r
- float moduleSize) {\r
- this.image = image;\r
- this.possibleCenters = new Vector(5);\r
- this.startX = startX;\r
- this.startY = startY;\r
- this.width = width;\r
- this.height = height;\r
- this.moduleSize = moduleSize;\r
- }\r
-\r
- AlignmentPattern find() throws ReaderException {\r
- int startX = this.startX;\r
- int height = this.height;\r
- int maxJ = startX + width;\r
- int middleI = startY + (height >> 1);\r
- BitArray luminanceRow = new BitArray(width);\r
- int[] stateCount = new int[3]; // looking for 1 1 1\r
- for (int iGen = 0; iGen < height; iGen++) {\r
- // Search from middle outwards\r
- int i = middleI +\r
- ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1));\r
- image.getBlackRow(i, luminanceRow, startX, width);\r
- stateCount[0] = 0;\r
- stateCount[1] = 0;\r
- stateCount[2] = 0;\r
- int currentState = 0;\r
- int j = startX;\r
- // Burn off leading white pixels before anything else; if we start in the middle of\r
- // a white run, it doesn't make sense to count its length, since we don't know if the\r
- // white run continued to the left of the start point\r
- while (!luminanceRow.get(j - startX) && j < maxJ) {\r
- j++;\r
- }\r
- while (j < maxJ) {\r
- if (luminanceRow.get(j - startX)) {\r
- // Black pixel\r
- if (currentState == 1) { // Counting black pixels\r
- stateCount[currentState]++;\r
- } else { // Counting white pixels\r
- if (currentState == 2) { // A winner?\r
- if (foundPatternCross(stateCount)) { // Yes\r
- AlignmentPattern confirmed =\r
- handlePossibleCenter(stateCount, i, j);\r
- if (confirmed != null) {\r
- return confirmed;\r
- }\r
- }\r
- stateCount[0] = stateCount[2];\r
- stateCount[1] = 1;\r
- stateCount[2] = 0;\r
- currentState = 1;\r
- } else {\r
- stateCount[++currentState]++;\r
- }\r
- }\r
- } else { // White pixel\r
- if (currentState == 1) { // Counting black pixels\r
- currentState++;\r
- }\r
- stateCount[currentState]++;\r
- }\r
- j++;\r
- }\r
- if (foundPatternCross(stateCount)) {\r
- AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, maxJ);\r
- if (confirmed != null) {\r
- return confirmed;\r
- }\r
- }\r
-\r
- }\r
-\r
- // Hmm, nothing we saw was observed and confirmed twice. If we had\r
- // any guess at all, return it.\r
- if (!possibleCenters.isEmpty()) {\r
- return (AlignmentPattern) possibleCenters.elementAt(0);\r
- }\r
-\r
- throw new ReaderException("Could not find alignment pattern");\r
- }\r
-\r
- private static float centerFromEnd(int[] stateCount, int end) {\r
- return (float) (end - stateCount[2]) - stateCount[1] / 2.0f;\r
- }\r
-\r
- private boolean foundPatternCross(int[] stateCount) {\r
- float moduleSize = this.moduleSize;\r
- for (int i = 0; i < 3; i++) {\r
- if (2.0f * Math.abs(moduleSize - stateCount[i]) >= moduleSize) {\r
- return false;\r
- }\r
- }\r
- return true;\r
- }\r
-\r
- private float crossCheckVertical(int startI, int centerJ, int maxCount) {\r
- MonochromeBitmapSource image = this.image;\r
-\r
- int maxI = image.getHeight();\r
- int[] stateCount = new int[3];\r
- int i = startI;\r
- while (i >= 0 && image.isBlack(centerJ, i) && stateCount[1] <= maxCount) {\r
- stateCount[1]++;\r
- i--;\r
- }\r
- if (i < 0 || stateCount[1] > maxCount) {\r
- return Float.NaN;\r
- }\r
- while (i >= 0 && !image.isBlack(centerJ, i) && stateCount[0] <= maxCount) {\r
- stateCount[0]++;\r
- i--;\r
- }\r
- if (stateCount[0] > maxCount) {\r
- return Float.NaN;\r
- }\r
-\r
- i = startI + 1;\r
- while (i < maxI && image.isBlack(centerJ, i) &&\r
- stateCount[1] <= maxCount) {\r
- stateCount[1]++;\r
- i++;\r
- }\r
- if (i == maxI || stateCount[1] > maxCount) {\r
- return Float.NaN;\r
- }\r
- while (i < maxI && !image.isBlack(centerJ, i) &&\r
- stateCount[2] <= maxCount) {\r
- stateCount[2]++;\r
- i++;\r
- }\r
- if (stateCount[2] > maxCount) {\r
- return Float.NaN;\r
- }\r
-\r
- return\r
- foundPatternCross(stateCount) ?\r
- centerFromEnd(stateCount, i) :\r
- Float.NaN;\r
- }\r
-\r
- private AlignmentPattern handlePossibleCenter(int[] stateCount,\r
- int i,\r
- int j) {\r
- float centerJ = centerFromEnd(stateCount, j);\r
- float centerI = crossCheckVertical(i, (int) centerJ, 2 * stateCount[1]);\r
- if (!Float.isNaN(centerI)) {\r
- float estimatedModuleSize = (float) (stateCount[0] +\r
- stateCount[1] +\r
- stateCount[2]) / 3.0f;\r
- int max = possibleCenters.size();\r
- for (int index = 0; index < max; index++) {\r
- AlignmentPattern center = (AlignmentPattern) possibleCenters.elementAt(index);\r
- // Look for about the same center and module size:\r
- if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) {\r
- return new AlignmentPattern(centerJ, centerI, estimatedModuleSize);\r
- }\r
- }\r
- // Hadn't found this before; save it\r
- possibleCenters.addElement(new AlignmentPattern(centerJ, centerI, estimatedModuleSize));\r
- }\r
- return null;\r
- }\r
-\r
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode.detector;
-
-import com.google.zxing.MonochromeBitmapSource;
-import com.google.zxing.ReaderException;
-import com.google.zxing.common.BitMatrix;
-
-/**
- * @author srowen@google.com (Sean Owen)
- */
-public final class DefaultGridSampler extends GridSampler {
-
- protected BitMatrix sampleGrid(MonochromeBitmapSource image,
- FinderPattern topLeft,
- FinderPattern topRight,
- FinderPattern bottomLeft,
- AlignmentPattern alignmentPattern,
- int dimension) throws ReaderException {
- float bottomRightX;
- float bottomRightY;
- if (alignmentPattern != null) {
- bottomRightX = alignmentPattern.getX();
- bottomRightY = alignmentPattern.getY();
- } else {
- // Don't have an alignment pattern, just make up the bottom-right point
- bottomRightX = (topRight.getX() - topLeft.getX()) + bottomLeft.getX();
- bottomRightY = (topRight.getY() - topLeft.getY()) + bottomLeft.getY();
- }
-
- float dimMinusThree = (float) dimension - 3.5f;
- JAIPerspectiveTransform transform = JAIPerspectiveTransform.getQuadToQuad(
- 3.5f,
- 3.5f,
- dimMinusThree,
- 3.5f,
- 3.5f,
- dimMinusThree,
- dimMinusThree - 3.0f,
- dimMinusThree - 3.0f,
- topLeft.getX(),
- topLeft.getY(),
- topRight.getX(),
- topRight.getY(),
- bottomLeft.getX(),
- bottomLeft.getY(),
- bottomRightX,
- bottomRightY);
-
- BitMatrix bits = new BitMatrix(dimension);
- float[] points = new float[dimension << 1];
- for (int i = 0; i < dimension; i++) {
- int max = points.length;
- float iValue = (float) i + 0.5f;
- for (int j = 0; j < max; j += 2) {
- points[j] = (float) j + 0.5f;
- points[j + 1] = iValue;
- }
- transform.transform(points);
- // Quick check to see if points transformed to something inside the image;
- // sufficent to check the endpoints
- checkEndpoint(image, points);
- for (int j = 0; j < dimension; j++) {
- int offset = j << 1;
- if (image.isBlack((int) points[offset], (int) points[offset + 1])) {
- // Black(-ish) pixel
- bits.set(i, j);
- }
- }
- }
- return bits;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode.detector;
-
-import com.google.zxing.MonochromeBitmapSource;
-import com.google.zxing.ReaderException;
-import com.google.zxing.ResultPoint;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.qrcode.decoder.Version;
-
-/**
- * @author srowen@google.com (Sean Owen)
- */
-public final class Detector {
-
- private final MonochromeBitmapSource image;
-
- public Detector(MonochromeBitmapSource image) {
- this.image = image;
- }
-
- public DetectorResult detect() throws ReaderException {
-
- MonochromeBitmapSource image = this.image;
-
- FinderPatternFinder finder = new FinderPatternFinder(image);
- FinderPatternInfo info = finder.find();
-
- FinderPattern topLeft = info.getTopLeft();
- FinderPattern topRight = info.getTopRight();
- FinderPattern bottomLeft = info.getBottomLeft();
-
- float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft);
- int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize);
- Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension);
- int modulesBetweenFPCenters = provisionalVersion.getDimensionForVersion() - 7;
-
- // Guess where a "bottom right" finder pattern would have been
- float bottomRightX = topRight.getX() - topLeft.getX() + bottomLeft.getX();
- float bottomRightY = topRight.getY() - topLeft.getY() + bottomLeft.getY();
-
- AlignmentPattern alignmentPattern = null;
- // Anything above version 1 has an alignment pattern
- if (provisionalVersion.getAlignmentPatternCenters().length > 0) {
-
- // Estimate that alignment pattern is closer by 3 modules
- // from "bottom right" to known top left location
- float correctionToTopLeft = 1.0f - 3.0f / (float) modulesBetweenFPCenters;
- int estAlignmentX = (int) (topLeft.getX() + correctionToTopLeft * (bottomRightX - topLeft.getX()));
- int estAlignmentY = (int) (topLeft.getY() + correctionToTopLeft * (bottomRightY - topLeft.getY()));
-
- // Kind of arbitrary -- expand search radius before giving up
- for (int i = 4; i <= 16; i <<= 1) {
- try {
- alignmentPattern = findAlignmentInRegion(moduleSize,
- estAlignmentX,
- estAlignmentY,
- (float) i);
- break;
- } catch (ReaderException de) {
- // try next round
- }
- }
- if (alignmentPattern == null) {
- throw new ReaderException("Could not find alignment pattern");
- }
-
- }
-
- GridSampler sampler = GridSampler.getInstance();
- BitMatrix bits = sampler.sampleGrid(image,
- topLeft,
- topRight,
- bottomLeft,
- alignmentPattern,
- dimension);
-
- /*
- try {
- BufferedImage outImage =
- new BufferedImage(dimension,
- dimension,
- BufferedImage.TYPE_BYTE_BINARY);
- for (int i = 0; i < dimension; i++) {
- for (int j = 0; j < dimension; j++) {
- if (bits.get(i, j)) {
- outImage.setRGB(j, i, 0xFF000000);
- } else {
- outImage.setRGB(j, i, 0xFFFFFFFF);
- }
- }
- }
- ImageIO.write(outImage, "PNG",
- new File("/home/srowen/out.png"));
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- */
-
- ResultPoint[] points;
- if (alignmentPattern == null) {
- points = new ResultPoint[] { bottomLeft, topLeft, topRight };
- } else {
- points = new ResultPoint[] { bottomLeft, topLeft, topRight, alignmentPattern };
- }
- return new DetectorResult(bits, points);
- }
-
- private static int computeDimension(ResultPoint topLeft,
- ResultPoint topRight,
- ResultPoint bottomLeft,
- float moduleSize)
- throws ReaderException {
- int tltrCentersDimension =
- round(FinderPatternFinder.distance(topLeft, topRight) / moduleSize);
- int tlblCentersDimension =
- round(FinderPatternFinder.distance(topLeft, bottomLeft) / moduleSize);
- int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7;
- switch (dimension & 0x03) { // mod 4
- case 0:
- dimension++;
- break;
- // 1? do nothing
- case 2:
- dimension--;
- break;
- case 3:
- throw new ReaderException("Bad dimension: " + dimension);
- }
- return dimension;
- }
-
- private float calculateModuleSize(ResultPoint topLeft,
- ResultPoint topRight,
- ResultPoint bottomLeft) {
- // Take the average
- return (calculateModuleSizeOneWay(topLeft, topRight) +
- calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f;
- }
-
- private float calculateModuleSizeOneWay(ResultPoint pattern,
- ResultPoint otherPattern) {
- float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int) pattern.getX(),
- (int) pattern.getY(),
- (int) otherPattern.getX(),
- (int) otherPattern.getY());
- float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int) otherPattern.getX(),
- (int) otherPattern.getY(),
- (int) pattern.getX(),
- (int) pattern.getY());
- if (Float.isNaN(moduleSizeEst1)) {
- return moduleSizeEst2;
- }
- if (Float.isNaN(moduleSizeEst2)) {
- return moduleSizeEst1;
- }
- // Average them, and divide by 7 since we've counted the width of 3 black modules,
- // and 1 white and 1 black module on either side. Ergo, divide sum by 14.
- return (moduleSizeEst1 + moduleSizeEst2) / 14.0f;
- }
-
- private float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY) {
- float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);
- result += sizeOfBlackWhiteBlackRun(fromX, fromY, fromX - (toX - fromX), fromY - (toY - fromY));
- return result - 1.0f; // -1 because we counted the middle pixel twice
- }
-
- private float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) {
- // Mild variant of Bresenham's algorithm;
- // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
- boolean steep = Math.abs(toY - fromY) > Math.abs(toX - fromX);
- if (steep) {
- int temp = fromX;
- fromX = fromY;
- fromY = temp;
- temp = toX;
- toX = toY;
- toY = temp;
- }
-
- int dx = Math.abs(toX - fromX);
- int dy = Math.abs(toY - fromY);
- int error = -dx >> 1;
- int ystep = fromY < toY ? 1 : -1;
- int xstep = fromX < toX ? 1 : -1;
- int state = 0; // In black pixels, looking for white, first or second time
- for (int x = fromX, y = fromY; x != toX; x += xstep) {
-
- int realX = steep ? y : x;
- int realY = steep ? x : y;
- if (state == 1) { // In white pixels, looking for black
- if (image.isBlack(realX, realY)) {
- state++;
- }
- } else {
- if (!image.isBlack(realX, realY)) {
- state++;
- }
- }
-
- if (state == 3) { // Found black, white, black, and stumbled back onto white; done
- int diffX = x - fromX;
- int diffY = y - fromY;
- return (float) Math.sqrt((double) (diffX * diffX + diffY * diffY));
- }
- error += dy;
- if (error > 0) {
- y += ystep;
- error -= dx;
- }
- }
- // Hmm, couldn't find all of what we wanted -- don't know
- return Float.NaN;
- }
-
- private AlignmentPattern findAlignmentInRegion(float overallEstModuleSize,
- int estAlignmentX,
- int estAlignmentY,
- float allowanceFactor)
- throws ReaderException {
- // Look for an alignment pattern (3 modules in size) around where it
- // should be
- int allowance = (int) (allowanceFactor * overallEstModuleSize);
- int alignmentAreaLeftX = Math.max(0, estAlignmentX - allowance);
- int alignmentAreaRightX = Math.min(image.getWidth() - 1,
- estAlignmentX + allowance);
- int alignmentAreaTopY = Math.max(0, estAlignmentY - allowance);
- int alignmentAreaBottomY = Math.min(image.getHeight() - 1,
- estAlignmentY + allowance);
-
- AlignmentPatternFinder alignmentFinder =
- new AlignmentPatternFinder(
- image,
- alignmentAreaLeftX,
- alignmentAreaTopY,
- alignmentAreaRightX - alignmentAreaLeftX,
- alignmentAreaBottomY - alignmentAreaTopY,
- overallEstModuleSize);
- return alignmentFinder.find();
- }
-
- /**
- * Ends up being a bit faster than Math.round()
- */
- private static int round(float d) {
- return (int) (d + 0.5f);
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode.detector;
-
-import com.google.zxing.ResultPoint;
-import com.google.zxing.common.BitMatrix;
-
-/**
- * <p>Encapsulates the result of detecting a barcode in an image. This includes the raw
- * matrix of black/white pixels corresponding to the barcode, and possibly points of interest
- * in the image, like the location of finder patterns or corners of the barcode in the image.</p>
- *
- * @author srowen@google.com (Sean Owen)
- */
-public final class DetectorResult {
-
- private final BitMatrix bits;
- private final ResultPoint[] points;
-
- DetectorResult(BitMatrix bits, ResultPoint[] points) {
- this.bits = bits;
- this.points = points;
- }
-
- public BitMatrix getBits() {
- return bits;
- }
-
- public ResultPoint[] getPoints() {
- return points;
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode.detector;
-
-import com.google.zxing.ResultPoint;
-
-/**
- * @author srowen@google.com (Sean Owen)
- */
-public final class FinderPattern implements ResultPoint {
-
- private final float posX;
- private final float posY;
- private final float estimatedModuleSize;
- private int count;
-
- FinderPattern(float posX, float posY, float estimatedModuleSize) {
- this.posX = posX;
- this.posY = posY;
- this.estimatedModuleSize = estimatedModuleSize;
- this.count = 1;
- }
-
- public float getX() {
- return posX;
- }
-
- public float getY() {
- return posY;
- }
-
- float getEstimatedModuleSize() {
- return estimatedModuleSize;
- }
-
- int getCount() {
- return count;
- }
-
- void incrementCount() {
- this.count++;
- }
-
- boolean aboutEquals(float moduleSize, float i, float j) {
- return Math.abs(i - posY) <= moduleSize &&
- Math.abs(j - posX) <= moduleSize &&
- (Math.abs(moduleSize - estimatedModuleSize) <= 1.0f ||
- Math.abs(moduleSize - estimatedModuleSize) / estimatedModuleSize <= 0.1f);
- }
-
-}
+++ /dev/null
-/*\r
- * Copyright 2007 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package com.google.zxing.qrcode.detector;\r
-\r
-import com.google.zxing.MonochromeBitmapSource;\r
-import com.google.zxing.ReaderException;\r
-import com.google.zxing.ResultPoint;\r
-import com.google.zxing.common.BitArray;\r
-import com.google.zxing.common.Collections;\r
-import com.google.zxing.common.Comparator;\r
-\r
-import java.util.Vector;\r
-\r
-/**\r
- * <p>This class is not thread-safe and should not be reused.</p>\r
- *\r
- * @author srowen@google.com (Sean Owen)\r
- */\r
-final class FinderPatternFinder {\r
-\r
- private static final int CENTER_QUORUM = 2;\r
- private static final int BIG_SKIP = 3;\r
-\r
- private final MonochromeBitmapSource image;\r
- private final Vector possibleCenters;\r
- private boolean hasSkipped;\r
-\r
- FinderPatternFinder(MonochromeBitmapSource image) {\r
- this.image = image;\r
- this.possibleCenters = new Vector(5);\r
- }\r
-\r
- FinderPatternInfo find() throws ReaderException {\r
- int maxI = image.getHeight();\r
- int maxJ = image.getWidth();\r
- int[] stateCount = new int[5]; // looking for 1 1 3 1 1\r
- boolean done = false;\r
- // We can afford to examine every few lines until we've started finding\r
- // the patterns\r
- int iSkip = BIG_SKIP;\r
- for (int i = iSkip - 1; i < maxI && !done; i += iSkip) {\r
- BitArray luminanceRow = image.getBlackRow(i, null, 0, maxJ);\r
- stateCount[0] = 0;\r
- stateCount[1] = 0;\r
- stateCount[2] = 0;\r
- stateCount[3] = 0;\r
- stateCount[4] = 0;\r
- int currentState = 0;\r
- for (int j = 0; j < maxJ; j++) {\r
- if (luminanceRow.get(j)) {\r
- // Black pixel\r
- if ((currentState & 1) == 1) { // Counting white pixels\r
- currentState++;\r
- }\r
- stateCount[currentState]++;\r
- } else { // White pixel\r
- if ((currentState & 1) == 0) { // Counting black pixels\r
- if (currentState == 4) { // A winner?\r
- if (foundPatternCross(stateCount)) { // Yes\r
- boolean confirmed =\r
- handlePossibleCenter(stateCount, i, j);\r
- if (confirmed) {\r
- iSkip = 1; // Go back to examining each line\r
- if (hasSkipped) {\r
- done = haveMulitplyConfirmedCenters();\r
- } else {\r
- int rowSkip = findRowSkip();\r
- if (rowSkip > stateCount[2]) {\r
- // Skip rows between row of lower confirmed center\r
- // and top of presumed third confirmed center\r
- // but back up a bit to get a full chance of detecting\r
- // it, entire width of center of finder pattern\r
-\r
- // Skip by rowSkip, but back off by stateCount[2] (size of last center\r
- // of pattern we saw) to be conservative, and also back off by iSkip which\r
- // is about to be re-added\r
- i += rowSkip - stateCount[2] - iSkip;\r
- j = maxJ - 1;\r
- }\r
- }\r
- } else {\r
- // Advance to next black pixel\r
- do {\r
- j++;\r
- } while (j < maxJ && !luminanceRow.get(j));\r
- j--; // back up to that last white pixel\r
- }\r
- // Clear state to start looking again\r
- currentState = 0;\r
- stateCount[0] = 0;\r
- stateCount[1] = 0;\r
- stateCount[2] = 0;\r
- stateCount[3] = 0;\r
- stateCount[4] = 0;\r
- } else { // No, shift counts back by two\r
- stateCount[0] = stateCount[2];\r
- stateCount[1] = stateCount[3];\r
- stateCount[2] = stateCount[4];\r
- stateCount[3] = 1;\r
- stateCount[4] = 0;\r
- currentState = 3;\r
- }\r
- } else {\r
- stateCount[++currentState]++;\r
- }\r
- } else { // Counting white pixels\r
- stateCount[currentState]++;\r
- }\r
- }\r
- }\r
- if (foundPatternCross(stateCount)) {\r
- boolean confirmed = handlePossibleCenter(stateCount, i, maxJ);\r
- if (confirmed) {\r
- iSkip = stateCount[0];\r
- if (hasSkipped) {\r
- // Found a third one\r
- done = haveMulitplyConfirmedCenters();\r
- }\r
- }\r
- }\r
- }\r
-\r
- FinderPattern[] patternInfo = selectBestPatterns();\r
- patternInfo = orderBestPatterns(patternInfo);\r
- float totalModuleSize = 0.0f;\r
- for (int i = 0; i < patternInfo.length; i++) {\r
- totalModuleSize += patternInfo[i].getEstimatedModuleSize();\r
- }\r
-\r
- return new FinderPatternInfo(totalModuleSize / (float) patternInfo.length,\r
- patternInfo);\r
- }\r
-\r
- private static float centerFromEnd(int[] stateCount, int end) {\r
- return (float) (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0f;\r
- }\r
-\r
- private static boolean foundPatternCross(int[] stateCount) {\r
- int totalModuleSize = 0;\r
- for (int i = 0; i < 5; i++) {\r
- if (stateCount[i] == 0) {\r
- return false;\r
- }\r
- totalModuleSize += stateCount[i];\r
- }\r
- if (totalModuleSize < 7) {\r
- return false;\r
- }\r
- int moduleSize = totalModuleSize / 7;\r
- // Allow less than 50% deviance from 1-1-3-1-1 pattern\r
- return\r
- Math.abs(moduleSize - stateCount[0]) << 1 <= moduleSize &&\r
- Math.abs(moduleSize - stateCount[1]) << 1 <= moduleSize &&\r
- Math.abs(3 * moduleSize - stateCount[2]) << 1 <= 3 * moduleSize &&\r
- Math.abs(moduleSize - stateCount[3]) << 1 <= moduleSize &&\r
- Math.abs(moduleSize - stateCount[4]) << 1 <= moduleSize;\r
- }\r
-\r
- private float crossCheckVertical(int startI, int centerJ, int maxCount) {\r
- MonochromeBitmapSource image = this.image;\r
-\r
- int maxI = image.getHeight();\r
- int[] stateCount = new int[5];\r
-\r
- int i = startI;\r
- while (i >= 0 && image.isBlack(centerJ, i)) {\r
- stateCount[2]++;\r
- i--;\r
- }\r
- if (i < 0) {\r
- return Float.NaN;\r
- }\r
- while (i >= 0 && !image.isBlack(centerJ, i) && stateCount[1] <= maxCount) {\r
- stateCount[1]++;\r
- i--;\r
- }\r
- // If already too many modules in this state or ran off the edge:\r
- if (i < 0 || stateCount[1] > maxCount) {\r
- return Float.NaN;\r
- }\r
- while (i >= 0 && image.isBlack(centerJ, i) && stateCount[0] <= maxCount) {\r
- stateCount[0]++;\r
- i--;\r
- }\r
- if (i < 0 || stateCount[0] > maxCount) {\r
- return Float.NaN;\r
- }\r
-\r
- i = startI + 1;\r
- while (i < maxI && image.isBlack(centerJ, i)) {\r
- stateCount[2]++;\r
- i++;\r
- }\r
- if (i == maxI) {\r
- return Float.NaN;\r
- }\r
- while (i < maxI && !image.isBlack(centerJ, i) && stateCount[3] < maxCount) {\r
- stateCount[3]++;\r
- i++;\r
- }\r
- if (i == maxI || stateCount[3] >= maxCount) {\r
- return Float.NaN;\r
- }\r
- while (i < maxI && image.isBlack(centerJ, i) && stateCount[4] < maxCount) {\r
- stateCount[4]++;\r
- i++;\r
- }\r
- if (stateCount[4] >= maxCount) {\r
- return Float.NaN;\r
- }\r
-\r
- return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : Float.NaN;\r
- }\r
-\r
- private float crossCheckHorizontal(int startJ, int centerI, int maxCount) {\r
- MonochromeBitmapSource image = this.image;\r
-\r
- int maxJ = image.getWidth();\r
- int[] stateCount = new int[5];\r
-\r
- int j = startJ;\r
- while (j >= 0 && image.isBlack(j, centerI)) {\r
- stateCount[2]++;\r
- j--;\r
- }\r
- if (j < 0) {\r
- return Float.NaN;\r
- }\r
- while (j >= 0 && !image.isBlack(j, centerI) && stateCount[1] <= maxCount) {\r
- stateCount[1]++;\r
- j--;\r
- }\r
- // If already too many modules in this state or ran off the edge:\r
- if (j < 0 || stateCount[1] > maxCount) {\r
- return Float.NaN;\r
- }\r
- while (j >= 0 && image.isBlack(j, centerI) && stateCount[0] <= maxCount) {\r
- stateCount[0]++;\r
- j--;\r
- }\r
- if (j < 0 || stateCount[0] > maxCount) {\r
- return Float.NaN;\r
- }\r
-\r
- j = startJ + 1;\r
- while (j < maxJ && image.isBlack(j, centerI)) {\r
- stateCount[2]++;\r
- j++;\r
- }\r
- if (j == maxJ) {\r
- return Float.NaN;\r
- }\r
- while (j < maxJ && !image.isBlack(j, centerI) && stateCount[3] < maxCount) {\r
- stateCount[3]++;\r
- j++;\r
- }\r
- if (j == maxJ || stateCount[3] >= maxCount) {\r
- return Float.NaN;\r
- }\r
- while (j < maxJ && image.isBlack(j, centerI) && stateCount[4] < maxCount) {\r
- stateCount[4]++;\r
- j++;\r
- }\r
- if (stateCount[4] >= maxCount) {\r
- return Float.NaN;\r
- }\r
-\r
- return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : Float.NaN;\r
- }\r
-\r
- private boolean handlePossibleCenter(int[] stateCount,\r
- int i,\r
- int j) {\r
- float centerJ = centerFromEnd(stateCount, j);\r
- float centerI = crossCheckVertical(i, (int) centerJ, stateCount[2]);\r
- if (!Float.isNaN(centerI)) {\r
- // Re-cross check\r
- centerJ = crossCheckHorizontal((int) centerJ, (int) centerI, stateCount[2]);\r
- if (!Float.isNaN(centerJ)) {\r
- float estimatedModuleSize = (float) (stateCount[0] +\r
- stateCount[1] +\r
- stateCount[2] +\r
- stateCount[3] +\r
- stateCount[4]) / 7.0f;\r
- boolean found = false;\r
- int max = possibleCenters.size();\r
- for (int index = 0; index < max; index++) {\r
- FinderPattern center = (FinderPattern) possibleCenters.elementAt(index);\r
- // Look for about the same center and module size:\r
- if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) {\r
- center.incrementCount();\r
- found = true;\r
- break;\r
- }\r
- }\r
- if (!found) {\r
- possibleCenters.addElement(\r
- new FinderPattern(centerJ, centerI, estimatedModuleSize));\r
- }\r
- return true;\r
- }\r
- }\r
- return false;\r
- }\r
-\r
- private int findRowSkip() {\r
- int max = possibleCenters.size();\r
- if (max <= 1) {\r
- return 0;\r
- }\r
- FinderPattern firstConfirmedCenter = null;\r
- for (int i = 0; i < max; i++) {\r
- FinderPattern center = (FinderPattern) possibleCenters.elementAt(i);\r
- if (center.getCount() >= CENTER_QUORUM) {\r
- if (firstConfirmedCenter == null) {\r
- firstConfirmedCenter = center;\r
- } else {\r
- // We have two confirmed centers\r
- // How far down can we skip before resuming looking for the next\r
- // pattern? In the worst case, only the difference between the\r
- // difference in the x / y coordinates of the two centers.\r
- // This is the case where you find top left first. Draw it out.\r
- hasSkipped = true;\r
- return (int) Math.abs(Math.abs(firstConfirmedCenter.getX() - center.getX()) -\r
- Math.abs(firstConfirmedCenter.getY() - center.getY()));\r
- }\r
- }\r
- }\r
- return 0;\r
- }\r
-\r
- private boolean haveMulitplyConfirmedCenters() {\r
- int count = 0;\r
- int max = possibleCenters.size();\r
- for (int i = 0; i < max; i++) {\r
- if (((FinderPattern) possibleCenters.elementAt(i)).getCount() >= CENTER_QUORUM) {\r
- if (++count == 3) {\r
- return true;\r
- }\r
- }\r
- }\r
- return false;\r
- }\r
-\r
- private FinderPattern[] selectBestPatterns() throws ReaderException {\r
- Collections.insertionSort(possibleCenters, new CenterComparator());\r
- int size = 0;\r
- int max = possibleCenters.size();\r
- while (size < max) {\r
- if (((FinderPattern) possibleCenters.elementAt(size)).getCount() < CENTER_QUORUM) {\r
- break;\r
- }\r
- size++;\r
- }\r
-\r
- if (size < 3) {\r
- // Couldn't find enough finder patterns\r
- throw new ReaderException("Could not find three finder patterns");\r
- }\r
-\r
- if (size == 3) {\r
- // Found just enough -- hope these are good!\r
- // toArray() is not available\r
- FinderPattern[] result = new FinderPattern[possibleCenters.size()];\r
- for (int i = 0; i < possibleCenters.size(); i++) {\r
- result[i] = (FinderPattern) possibleCenters.elementAt(i);\r
- }\r
- return result;\r
- }\r
-\r
- possibleCenters.setSize(size);\r
-\r
- // Hmm, multiple found. We need to pick the best three. Find the most\r
- // popular ones whose module size is nearest the average\r
-\r
- float averageModuleSize = 0.0f;\r
- for (int i = 0; i < size; i++) {\r
- averageModuleSize += ((FinderPattern) possibleCenters.elementAt(i)).getEstimatedModuleSize();\r
- }\r
- averageModuleSize /= (float) size;\r
-\r
- Collections.insertionSort(\r
- possibleCenters,\r
- new ClosestToAverageComparator(averageModuleSize));\r
-\r
- //return confirmedCenters.subList(0, 3).toArray(new FinderPattern[3]);\r
- FinderPattern[] result = new FinderPattern[3];\r
- for (int i = 0; i < 3; i++) {\r
- result[i] = (FinderPattern) possibleCenters.elementAt(i);\r
- }\r
- return result;\r
- }\r
-\r
- private static FinderPattern[] orderBestPatterns(FinderPattern[] patterns) {\r
-\r
- // Find distances between pattern centers\r
- float abDistance = distance(patterns[0], patterns[1]);\r
- float bcDistance = distance(patterns[1], patterns[2]);\r
- float acDistance = distance(patterns[0], patterns[2]);\r
-\r
- FinderPattern topLeft;\r
- FinderPattern topRight;\r
- FinderPattern bottomLeft;\r
- // Assume one closest to other two is top left\r
- if (bcDistance >= abDistance && bcDistance >= acDistance) {\r
- topLeft = patterns[0];\r
- topRight = patterns[1]; // These two are guesses at the moment\r
- bottomLeft = patterns[2];\r
- } else if (acDistance >= bcDistance && acDistance >= abDistance) {\r
- topLeft = patterns[1];\r
- topRight = patterns[0];\r
- bottomLeft = patterns[2];\r
- } else {\r
- topLeft = patterns[2];\r
- topRight = patterns[0];\r
- bottomLeft = patterns[1];\r
- }\r
-\r
- // Use cross product to figure out which of other1/2 is the bottom left\r
- // pattern. The vector "top-left -> bottom-left" x "top-left -> top-right"\r
- // should yield a vector with positive z component\r
- if ((bottomLeft.getY() - topLeft.getY()) * (topRight.getX() - topLeft.getX()) <\r
- (bottomLeft.getX() - topLeft.getX()) * (topRight.getY() - topLeft.getY())) {\r
- FinderPattern temp = topRight;\r
- topRight = bottomLeft;\r
- bottomLeft = temp;\r
- }\r
-\r
- return new FinderPattern[]{bottomLeft, topLeft, topRight};\r
- }\r
-\r
- static float distance(ResultPoint pattern1, ResultPoint pattern2) {\r
- float xDiff = pattern1.getX() - pattern2.getX();\r
- float yDiff = pattern1.getY() - pattern2.getY();\r
- return (float) Math.sqrt((double) (xDiff * xDiff + yDiff * yDiff));\r
- }\r
-\r
- private static class CenterComparator implements Comparator {\r
- public int compare(Object center1, Object center2) {\r
- return ((FinderPattern) center2).getCount() - ((FinderPattern) center1).getCount();\r
- }\r
- }\r
-\r
- private static class ClosestToAverageComparator implements Comparator {\r
- private float averageModuleSize;\r
-\r
- private ClosestToAverageComparator(float averageModuleSize) {\r
- this.averageModuleSize = averageModuleSize;\r
- }\r
-\r
- public int compare(Object center1, Object center2) {\r
- return\r
- Math.abs(((FinderPattern) center1).getEstimatedModuleSize() - averageModuleSize) <\r
- Math.abs(((FinderPattern) center2).getEstimatedModuleSize() - averageModuleSize) ?\r
- -1 :\r
- 1;\r
- }\r
- }\r
-\r
-}\r
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode.detector;
-
-/**
- * @author srowen@google.com (Sean Owen)
- */
-final class FinderPatternInfo {
-
- private final float rawEstimatedModuleSize;
- private final FinderPattern bottomLeft;
- private final FinderPattern topLeft;
- private final FinderPattern topRight;
-
- FinderPatternInfo(float rawEstimatedModuleSize,
- FinderPattern[] patternCenters) {
- this.rawEstimatedModuleSize = rawEstimatedModuleSize;
- this.bottomLeft = patternCenters[0];
- this.topLeft = patternCenters[1];
- this.topRight = patternCenters[2];
- }
-
- float getRawEstimatedModuleSize() {
- return rawEstimatedModuleSize;
- }
-
- FinderPattern getBottomLeft() {
- return bottomLeft;
- }
-
- FinderPattern getTopLeft() {
- return topLeft;
- }
-
- FinderPattern getTopRight() {
- return topRight;
- }
-
-}
+++ /dev/null
-/*
- * Copyright 2007 Google Inc.
- *
- * 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.google.zxing.qrcode.detector;
-
-import com.google.zxing.MonochromeBitmapSource;
-import com.google.zxing.ReaderException;
-import com.google.zxing.common.BitMatrix;
-
-/**
- * Implementations of this class can, given locations of finder patterns for a QR code in an
- * image, sample the right points in the image to reconstruct the QR code, accounting for
- * perspective distortion. It is abstracted since it is relatively expensive and should be allowed
- * to take advantage of platform-specific optimized implementations, like Sun's Java Advanced
- * Imaging library, but which may not be available in other environments such as J2ME, and vice
- * versa.
- *
- * The implementation used can be controlled by calling {@link #setGridSamplerClassName(String)}
- * with the name of a class which implements this interface.
- *
- * @author srowen@google.com (Sean Owen)
- */
-public abstract class GridSampler {
-
- private static final String DEFAULT_IMPL_CLASS =
- "com.google.zxing.qrcode.detector.DefaultGridSampler";
-
- private static String gridSamplerClassName = DEFAULT_IMPL_CLASS;
- private static GridSampler gridSampler;
-
- public static void setGridSamplerClassName(String className) {
- if (className == null) {
- throw new IllegalArgumentException();
- }
- gridSamplerClassName = className;
- }
-
- public static GridSampler getInstance() {
- if (gridSampler == null) {
- try {
- Class gridSamplerClass = Class.forName(gridSamplerClassName);
- gridSampler = (GridSampler) gridSamplerClass.newInstance();
- } catch (ClassNotFoundException cnfe) {
- throw new RuntimeException(cnfe.toString());
- } catch (IllegalAccessException iae) {
- throw new RuntimeException(iae.toString());
- } catch (InstantiationException ie) {
- throw new RuntimeException(ie.toString());
- }
- }
- return gridSampler;
- }
-
- protected abstract BitMatrix sampleGrid(MonochromeBitmapSource image,
- FinderPattern topLeft,
- FinderPattern topRight,
- FinderPattern bottomLeft,
- AlignmentPattern alignmentPattern,
- int dimension) throws ReaderException;
-
- protected static void checkEndpoint(MonochromeBitmapSource image, float[] points)
- throws ReaderException {
- int x = (int) points[0];
- int y = (int) points[1];
- if (x < 0 || x >= image.getWidth() || y < 0 || y >= image.getHeight()) {
- throw new ReaderException("Transformed point out of bounds at " + x + ',' + y);
- }
- x = (int) points[points.length - 2];
- y = (int) points[points.length - 1];
- if (x < 0 || x >= image.getWidth() || y < 0 || y >= image.getHeight()) {
- throw new ReaderException("Transformed point out of bounds at " + x + ',' + y);
- }
- }
-
-}
+++ /dev/null
-package com.google.zxing.qrcode.detector;
-
-/**
- * TODO need to reimplement this from scratch. This is derived from jai-core from Sun
- * and it is not clear we can redistribute this modification.
- */
-final class JAIPerspectiveTransform {
-
- private float m00, m01, m02, m10, m11, m12, m20, m21, m22;
-
- JAIPerspectiveTransform() {
- m00 = m11 = m22 = 1.0f;
- m01 = m02 = m10 = m12 = m20 = m21 = 0.0f;
- }
-
- private void makeAdjoint() {
- float m00p = m11 * m22 - m12 * m21;
- float m01p = m12 * m20 - m10 * m22; // flipped sign
- float m02p = m10 * m21 - m11 * m20;
- float m10p = m02 * m21 - m01 * m22; // flipped sign
- float m11p = m00 * m22 - m02 * m20;
- float m12p = m01 * m20 - m00 * m21; // flipped sign
- float m20p = m01 * m12 - m02 * m11;
- float m21p = m02 * m10 - m00 * m12; // flipped sign
- float m22p = m00 * m11 - m01 * m10;
- // Transpose and copy sub-determinants
- m00 = m00p;
- m01 = m10p;
- m02 = m20p;
- m10 = m01p;
- m11 = m11p;
- m12 = m21p;
- m20 = m02p;
- m21 = m12p;
- m22 = m22p;
- }
-
- private static void getSquareToQuad(float x0, float y0,
- float x1, float y1,
- float x2, float y2,
- float x3, float y3,
- JAIPerspectiveTransform tx) {
- float dx3 = x0 - x1 + x2 - x3;
- float dy3 = y0 - y1 + y2 - y3;
- tx.m22 = 1.0f;
- if ((dx3 == 0.0f) && (dy3 == 0.0f)) { // to do: use tolerance
- tx.m00 = x1 - x0;
- tx.m01 = x2 - x1;
- tx.m02 = x0;
- tx.m10 = y1 - y0;
- tx.m11 = y2 - y1;
- tx.m12 = y0;
- tx.m20 = 0.0f;
- tx.m21 = 0.0f;
- } else {
- float dx1 = x1 - x2;
- float dy1 = y1 - y2;
- float dx2 = x3 - x2;
- float dy2 = y3 - y2;
- float invdet = 1.0f / (dx1 * dy2 - dx2 * dy1);
- tx.m20 = (dx3 * dy2 - dx2 * dy3) * invdet;
- tx.m21 = (dx1 * dy3 - dx3 * dy1) * invdet;
- tx.m00 = x1 - x0 + tx.m20 * x1;
- tx.m01 = x3 - x0 + tx.m21 * x3;
- tx.m02 = x0;
- tx.m10 = y1 - y0 + tx.m20 * y1;
- tx.m11 = y3 - y0 + tx.m21 * y3;
- tx.m12 = y0;
- }
- }
-
- private static JAIPerspectiveTransform getSquareToQuad(float x0, float y0,
- float x1, float y1,
- float x2, float y2,
- float x3, float y3) {
- JAIPerspectiveTransform tx = new JAIPerspectiveTransform();
- getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx);
- return tx;
- }
-
- private static JAIPerspectiveTransform getQuadToSquare(float x0, float y0,
- float x1, float y1,
- float x2, float y2,
- float x3, float y3) {
- JAIPerspectiveTransform tx = new JAIPerspectiveTransform();
- getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx);
- tx.makeAdjoint();
- return tx;
- }
-
- static JAIPerspectiveTransform getQuadToQuad(float x0, float y0,
- float x1, float y1,
- float x2, float y2,
- float x3, float y3,
- float x0p, float y0p,
- float x1p, float y1p,
- float x2p, float y2p,
- float x3p, float y3p) {
- JAIPerspectiveTransform tx1 = getQuadToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
- JAIPerspectiveTransform tx2 = getSquareToQuad(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
- tx1.concatenate(tx2);
- return tx1;
- }
-
- private void concatenate(JAIPerspectiveTransform Tx) {
- float m00p = m00 * Tx.m00 + m10 * Tx.m01 + m20 * Tx.m02;
- float m10p = m00 * Tx.m10 + m10 * Tx.m11 + m20 * Tx.m12;
- float m20p = m00 * Tx.m20 + m10 * Tx.m21 + m20 * Tx.m22;
- float m01p = m01 * Tx.m00 + m11 * Tx.m01 + m21 * Tx.m02;
- float m11p = m01 * Tx.m10 + m11 * Tx.m11 + m21 * Tx.m12;
- float m21p = m01 * Tx.m20 + m11 * Tx.m21 + m21 * Tx.m22;
- float m02p = m02 * Tx.m00 + m12 * Tx.m01 + m22 * Tx.m02;
- float m12p = m02 * Tx.m10 + m12 * Tx.m11 + m22 * Tx.m12;
- float m22p = m02 * Tx.m20 + m12 * Tx.m21 + m22 * Tx.m22;
- m00 = m00p;
- m10 = m10p;
- m20 = m20p;
- m01 = m01p;
- m11 = m11p;
- m21 = m21p;
- m02 = m02p;
- m12 = m12p;
- m22 = m22p;
- }
-
- void transform(float[] points) {
- int max = points.length;
- for (int offset = 0; offset < max; offset += 2) {
- float x = points[offset];
- float y = points[offset + 1];
- float w = m20 * x + m21 * y + m22;
- if (w == 0.0f) {
- points[offset] = x;
- points[offset + 1] = y;
- } else {
- float oneOverW = 1.0f / w;
- points[offset] = (m00 * x + m01 * y + m02) * oneOverW;
- points[offset + 1] = (m10 * x + m11 * y + m12) * oneOverW;
- }
- }
- }
-}
\ No newline at end of file