+
+ZXing ("zebra crossing") is an open-source, multi-format 1D/2D barcode image processing
+library implemented in Java, with ports to other languages.
+
+## Supported Formats
+
+| 1D product | 1D industrial | 2D
+| ---------- | ------------- | --------------
+| UPC-A | Code 39 | QR Code
+| UPC-E | Code 93 | Data Matrix
+| EAN-8 | Code 128 | Aztec (beta)
+| EAN-13 | Codabar | PDF 417 (beta)
+| | ITF |
+| | RSS-14 |
+| | RSS-Expanded |
+
+## Components
+
+### Active
+
+| Module | Description
+| ------------------- | -----------
+| core | The core image decoding library, and test code
+| javase | JavaSE-specific client code
+| android | Android client Barcode Scanner [](https://play.google.com/store/apps/details?id=com.google.zxing.client.android)
+| androidtest | Android test app, ZXing Test
+| android-integration | Supports integration with Barcode Scanner via `Intent`
+| android-core | Android-related code shared among `android`, `androidtest`, `glass`
+| glass | Simple Google Glass application
+| zxingorg | The source behind `zxing.org`
+| zxing.appspot.com | The source behind web-based barcode generator at `zxing.appspot.com`
+
+### Available in previous releases
+
+| Module | Description
+| ------ | -----------
+| [cpp](https://github.com/zxing/zxing/tree/00f634024ceeee591f54e6984ea7dd666fab22ae/cpp) | C++ port
+| [iphone](https://github.com/zxing/zxing/tree/00f634024ceeee591f54e6984ea7dd666fab22ae/iphone) | iPhone client
+| [objc](https://github.com/zxing/zxing/tree/00f634024ceeee591f54e6984ea7dd666fab22ae/objc) | Objective C port
+| [actionscript](https://github.com/zxing/zxing/tree/c1df162b95e07928afbd4830798cc1408af1ac67/actionscript) | Partial ActionScript port
+| [jruby](https://github.com/zxing/zxing/tree/a95a8fee842f67fb43799a8e0e70e4c68b509c43/jruby) | JRuby wrapper
+
+### ZXing-based third-party open source projects
+
+| Module | Description
+| --------------------------------------------------------------- | -----------
+| [QZXing](https://sourceforge.net/projects/qzxing) | port to Qt framework
+| [zxing-cpp](https://github.com/glassechidna/zxing-cpp) | port to C++ (forked from the [deprecated official C++ port](https://github.com/zxing/zxing/tree/00f634024ceeee591f54e6984ea7dd666fab22ae/cpp))
+| [zxing_cpp.rb](https://github.com/glassechidna/zxing_cpp.rb) | bindings for Ruby (not just JRuby), powered by [zxing-cpp](https://github.com/glassechidna/zxing-cpp)
+| [python-zxing](https://github.com/oostendo/python-zxing) | bindings for Python
+| [ZXing .NET](http://zxingnet.codeplex.com/) | port to .NET and C#, and related Windows platform
+
+### Other related third-party open source projects
+
+| Module | Description
+| ---------------------------------------------- | -----------
+| [Barcode4J](http://barcode4j.sourceforge.net/) | Generator library in Java
+| [ZBar](http://zbar.sourceforge.net/) | Reader library in C99
+| [OkapiBarcode](https://github.com/woo-j/OkapiBarcode) |
+
+## Links
+
+* [Online Decoder](http://zxing.org/w/decode.jspx)
+* [QR Code Generator](http://zxing.appspot.com/generator)
+* [Javadoc](http://zxing.github.io/zxing/apidocs/)
+* [Documentation Site](http://zxing.github.io/zxing/)
+* [Google+](https://plus.google.com/u/0/b/105889184633382354358/105889184633382354358/posts)
+
+## Contacting
+
+Post to the [discussion forum](https://groups.google.com/group/zxing) or tag a question with [`zxing`
+on StackOverflow](http://stackoverflow.com/questions/tagged/zxing).
+
+## Etcetera
+
+[](https://travis-ci.org/zxing/zxing)
+[](https://scan.coverity.com/projects/1924)
+[](https://codecov.io/github/zxing/zxing?branch=master)
+
+QR code is trademarked by Denso Wave, inc. Thanks to Haase & Martin OHG for contributing the logo.
+
+Optimized with [](http://www.ej-technologies.com/products/jprofiler/overview.html)
diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/BarcodeFormat.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/BarcodeFormat.java
new file mode 100644
index 000000000..7f6a0ef58
--- /dev/null
+++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/BarcodeFormat.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2007 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zxing;
+
+/**
+ * Enumerates barcode formats known to this package. Please keep alphabetized.
+ *
+ * @author Sean Owen
+ */
+public enum BarcodeFormat {
+
+ /** Aztec 2D barcode format. */
+ AZTEC,
+
+ /** CODABAR 1D format. */
+ CODABAR,
+
+ /** Code 39 1D format. */
+ CODE_39,
+
+ /** Code 93 1D format. */
+ CODE_93,
+
+ /** Code 128 1D format. */
+ CODE_128,
+
+ /** Data Matrix 2D barcode format. */
+ DATA_MATRIX,
+
+ /** EAN-8 1D format. */
+ EAN_8,
+
+ /** EAN-13 1D format. */
+ EAN_13,
+
+ /** ITF (Interleaved Two of Five) 1D format. */
+ ITF,
+
+ /** MaxiCode 2D barcode format. */
+ MAXICODE,
+
+ /** PDF417 format. */
+ PDF_417,
+
+ /** QR Code 2D barcode format. */
+ QR_CODE,
+
+ /** RSS 14 */
+ RSS_14,
+
+ /** RSS EXPANDED */
+ RSS_EXPANDED,
+
+ /** UPC-A 1D format. */
+ UPC_A,
+
+ /** UPC-E 1D format. */
+ UPC_E,
+
+ /** UPC/EAN extension format. Not a stand-alone format. */
+ UPC_EAN_EXTENSION
+
+}
diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/ChecksumException.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/ChecksumException.java
new file mode 100644
index 000000000..c5acbe3ee
--- /dev/null
+++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/ChecksumException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2007 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zxing;
+
+/**
+ * Thrown when a barcode was successfully detected and decoded, but
+ * was not returned because its checksum feature failed.
+ *
+ * @author Sean Owen
+ */
+public final class ChecksumException extends ReaderException {
+
+ private static final ChecksumException INSTANCE = new ChecksumException();
+ static {
+ INSTANCE.setStackTrace(NO_TRACE); // since it's meaningless
+ }
+
+ private ChecksumException() {
+ // do nothing
+ }
+
+ private ChecksumException(Throwable cause) {
+ super(cause);
+ }
+
+ public static ChecksumException getChecksumInstance() {
+ return isStackTrace ? new ChecksumException() : INSTANCE;
+ }
+
+ public static ChecksumException getChecksumInstance(Throwable cause) {
+ return isStackTrace ? new ChecksumException(cause) : INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/EncodeHintType.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/EncodeHintType.java
new file mode 100644
index 000000000..eb7938e42
--- /dev/null
+++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/EncodeHintType.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zxing;
+
+/**
+ * These are a set of hints that you may pass to Writers to specify their behavior.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public enum EncodeHintType {
+
+ /**
+ * Specifies what degree of error correction to use, for example in QR Codes.
+ * Type depends on the encoder. For example for QR codes it's type
+ * {@link com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ErrorCorrectionLevel}.
+ * For Aztec it is of type {@link Integer}, representing the minimal percentage of error correction words.
+ * For PDF417 it is of type {@link Integer}, valid values being 0 to 8.
+ * In all cases, it can also be a {@link String} representation of the desired value as well.
+ * Note: an Aztec symbol should have a minimum of 25% EC words.
+ */
+ ERROR_CORRECTION,
+
+ /**
+ * Specifies what character encoding to use where applicable (type {@link String})
+ */
+ CHARACTER_SET,
+
+ /**
+ * Specifies the matrix shape for Data Matrix (type {@link com.google.zxing.datamatrix.encoder.SymbolShapeHint})
+ */
+ DATA_MATRIX_SHAPE,
+
+ /**
+ * Specifies a minimum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
+ *
+ * @deprecated use width/height params in
+ * {@link com.google.zxing.datamatrix.DataMatrixWriter#encode(String, BarcodeFormat, int, int)}
+ */
+ @Deprecated
+ MIN_SIZE,
+
+ /**
+ * Specifies a maximum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
+ *
+ * @deprecated without replacement
+ */
+ @Deprecated
+ MAX_SIZE,
+
+ /**
+ * Specifies margin, in pixels, to use when generating the barcode. The meaning can vary
+ * by format; for example it controls margin before and after the barcode horizontally for
+ * most 1D formats. (Type {@link Integer}, or {@link String} representation of the integer value).
+ */
+ MARGIN,
+
+ /**
+ * Specifies whether to use compact mode for PDF417 (type {@link Boolean}, or "true" or "false"
+ * {@link String} value).
+ */
+ PDF417_COMPACT,
+
+ /**
+ * Specifies what compaction mode to use for PDF417 (type
+ * {@link com.google.zxing.pdf417.encoder.Compaction Compaction} or {@link String} value of one of its
+ * enum values).
+ */
+ PDF417_COMPACTION,
+
+ /**
+ * Specifies the minimum and maximum number of rows and columns for PDF417 (type
+ * {@link com.google.zxing.pdf417.encoder.Dimensions Dimensions}).
+ */
+ PDF417_DIMENSIONS,
+
+ /**
+ * Specifies the required number of layers for an Aztec code.
+ * A negative number (-1, -2, -3, -4) specifies a compact Aztec code.
+ * 0 indicates to use the minimum number of layers (the default).
+ * A positive number (1, 2, .. 32) specifies a normal (non-compact) Aztec code.
+ * (Type {@link Integer}, or {@link String} representation of the integer value).
+ */
+ AZTEC_LAYERS,
+}
diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/FormatException.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/FormatException.java
new file mode 100644
index 000000000..b046b822d
--- /dev/null
+++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/FormatException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2007 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zxing;
+
+/**
+ * Thrown when a barcode was successfully detected, but some aspect of
+ * the content did not conform to the barcode's format rules. This could have
+ * been due to a mis-detection.
+ *
+ * @author Sean Owen
+ */
+public final class FormatException extends ReaderException {
+
+ private static final FormatException INSTANCE = new FormatException();
+ static {
+ INSTANCE.setStackTrace(NO_TRACE); // since it's meaningless
+ }
+
+ private FormatException() {
+ }
+
+ private FormatException(Throwable cause) {
+ super(cause);
+ }
+
+ public static FormatException getFormatInstance() {
+ return isStackTrace ? new FormatException() : INSTANCE;
+ }
+
+ public static FormatException getFormatInstance(Throwable cause) {
+ return isStackTrace ? new FormatException(cause) : INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/ReaderException.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/ReaderException.java
new file mode 100644
index 000000000..5f2c12e43
--- /dev/null
+++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/ReaderException.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2007 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.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 Sean Owen
+ */
+public abstract class ReaderException extends Exception {
+
+ // disable stack traces when not running inside test units
+ protected static final boolean isStackTrace =
+ System.getProperty("surefire.test.class.path") != null;
+ protected static final StackTraceElement[] NO_TRACE = new StackTraceElement[0];
+
+ ReaderException() {
+ // do nothing
+ }
+
+ ReaderException(Throwable cause) {
+ super(cause);
+ }
+
+ // Prevent stack traces from being taken
+ // srowen says: huh, my IDE is saying this is not an override. native methods can't be overridden?
+ // This, at least, does not hurt. Because we use a singleton pattern here, it doesn't matter anyhow.
+ @Override
+ public final Throwable fillInStackTrace() {
+ return null;
+ }
+
+}
diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/Writer.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/Writer.java
new file mode 100644
index 000000000..f405fd844
--- /dev/null
+++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/Writer.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zxing;
+
+import com.google.zxing.common.BitMatrix;
+
+import java.util.Map;
+
+/**
+ * The base class for all objects which encode/generate a barcode image.
+ *
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+public interface Writer {
+
+ /**
+ * Encode a barcode using the default settings.
+ *
+ * @param contents The contents to encode in the barcode
+ * @param format The barcode format to generate
+ * @param width The preferred width in pixels
+ * @param height The preferred height in pixels
+ * @return {@link BitMatrix} representing encoded barcode image
+ * @throws WriterException if contents cannot be encoded legally in a format
+ */
+ BitMatrix encode(String contents, BarcodeFormat format, int width, int height)
+ throws WriterException;
+
+ /**
+ * @param contents The contents to encode in the barcode
+ * @param format The barcode format to generate
+ * @param width The preferred width in pixels
+ * @param height The preferred height in pixels
+ * @param hints Additional parameters to supply to the encoder
+ * @return {@link BitMatrix} representing encoded barcode image
+ * @throws WriterException if contents cannot be encoded legally in a format
+ */
+ BitMatrix encode(String contents,
+ BarcodeFormat format,
+ int width,
+ int height,
+ MapA simple, fast array of bits, represented compactly by an array of ints internally.
+ * + * @author Sean Owen + */ +public final class BitArray implements Cloneable { + + private int[] bits; + private int size; + + public BitArray() { + this.size = 0; + this.bits = new int[1]; + } + + public BitArray(int size) { + this.size = size; + this.bits = makeArray(size); + } + + // For testing only + BitArray(int[] bits, int size) { + this.bits = bits; + this.size = size; + } + + public int getSize() { + return size; + } + + public int getSizeInBytes() { + return (size + 7) / 8; + } + + private void ensureCapacity(int size) { + if (size > bits.length * 32) { + int[] newBits = makeArray(size); + System.arraycopy(bits, 0, newBits, 0, bits.length); + this.bits = newBits; + } + } + + /** + * @param i bit to get + * @return true iff bit i is set + */ + public boolean get(int i) { + return (bits[i / 32] & (1 << (i & 0x1F))) != 0; + } + + /** + * Sets bit i. + * + * @param i bit to set + */ + public void set(int i) { + bits[i / 32] |= 1 << (i & 0x1F); + } + + /** + * Flips bit i. + * + * @param i bit to set + */ + public void flip(int i) { + bits[i / 32] ^= 1 << (i & 0x1F); + } + + /** + * @param from first bit to check + * @return index of first bit that is set, starting from the given index, or size if none are set + * at or beyond this given index + * @see #getNextUnset(int) + */ + public int getNextSet(int from) { + if (from >= size) { + return size; + } + int bitsOffset = from / 32; + int currentBits = bits[bitsOffset]; + // mask off lesser bits first + currentBits &= ~((1 << (from & 0x1F)) - 1); + while (currentBits == 0) { + if (++bitsOffset == bits.length) { + return size; + } + currentBits = bits[bitsOffset]; + } + int result = (bitsOffset * 32) + Integer.numberOfTrailingZeros(currentBits); + return result > size ? size : result; + } + + /** + * @param from index to start looking for unset bit + * @return index of next unset bit, or {@code size} if none are unset until the end + * @see #getNextSet(int) + */ + public int getNextUnset(int from) { + if (from >= size) { + return size; + } + int bitsOffset = from / 32; + int currentBits = ~bits[bitsOffset]; + // mask off lesser bits first + currentBits &= ~((1 << (from & 0x1F)) - 1); + while (currentBits == 0) { + if (++bitsOffset == bits.length) { + return size; + } + currentBits = ~bits[bitsOffset]; + } + int result = (bitsOffset * 32) + Integer.numberOfTrailingZeros(currentBits); + return result > size ? size : result; + } + + /** + * Sets a block of 32 bits, starting at bit i. + * + * @param i first bit to set + * @param newBits the new value of the next 32 bits. Note again that the least-significant bit + * corresponds to bit i, the next-least-significant to i+1, and so on. + */ + public void setBulk(int i, int newBits) { + bits[i / 32] = newBits; + } + + /** + * Sets a range of bits. + * + * @param start start of range, inclusive. + * @param end end of range, exclusive + */ + public void setRange(int start, int end) { + if (end < start) { + throw new IllegalArgumentException(); + } + if (end == start) { + return; + } + end--; // will be easier to treat this as the last actually set bit -- inclusive + int firstInt = start / 32; + int lastInt = end / 32; + for (int i = firstInt; i <= lastInt; i++) { + int firstBit = i > firstInt ? 0 : start & 0x1F; + int lastBit = i < lastInt ? 31 : end & 0x1F; + int mask; + if (firstBit == 0 && lastBit == 31) { + mask = -1; + } else { + mask = 0; + for (int j = firstBit; j <= lastBit; j++) { + mask |= 1 << j; + } + } + bits[i] |= mask; + } + } + + /** + * Clears all bits (sets to false). + */ + public void clear() { + int max = bits.length; + for (int i = 0; i < max; i++) { + bits[i] = 0; + } + } + + /** + * Efficient method to check if a range of bits is set, or not set. + * + * @param start start of range, inclusive. + * @param end end of range, exclusive + * @param value if true, checks that bits in range are set, otherwise checks that they are not set + * @return true iff all bits are set or not set in range, according to value argument + * @throws IllegalArgumentException if end is less than or equal to start + */ + public boolean isRange(int start, int end, boolean value) { + if (end < start) { + throw new IllegalArgumentException(); + } + if (end == start) { + return true; // empty range matches + } + end--; // will be easier to treat this as the last actually set bit -- inclusive + int firstInt = start / 32; + int lastInt = end / 32; + for (int i = firstInt; i <= lastInt; i++) { + int firstBit = i > firstInt ? 0 : start & 0x1F; + int lastBit = i < lastInt ? 31 : end & 0x1F; + int mask; + if (firstBit == 0 && lastBit == 31) { + mask = -1; + } else { + mask = 0; + for (int j = firstBit; j <= lastBit; j++) { + mask |= 1 << j; + } + } + + // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is, + // equals the mask, or we're looking for 0s and the masked portion is not all 0s + if ((bits[i] & mask) != (value ? mask : 0)) { + return false; + } + } + return true; + } + + public void appendBit(boolean bit) { + ensureCapacity(size + 1); + if (bit) { + bits[size / 32] |= 1 << (size & 0x1F); + } + size++; + } + + /** + * Appends the least-significant bits, from value, in order from most-significant to + * least-significant. For example, appending 6 bits from 0x000001E will append the bits + * 0, 1, 1, 1, 1, 0 in that order. + * + * @param value {@code int} containing bits to append + * @param numBits bits from value to append + */ + public void appendBits(int value, int numBits) { + if (numBits < 0 || numBits > 32) { + throw new IllegalArgumentException("Num bits must be between 0 and 32"); + } + ensureCapacity(size + numBits); + for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) { + appendBit(((value >> (numBitsLeft - 1)) & 0x01) == 1); + } + } + + public void appendBitArray(BitArray other) { + int otherSize = other.size; + ensureCapacity(size + otherSize); + for (int i = 0; i < otherSize; i++) { + appendBit(other.get(i)); + } + } + + public void xor(BitArray other) { + if (bits.length != other.bits.length) { + throw new IllegalArgumentException("Sizes don't match"); + } + for (int i = 0; i < bits.length; i++) { + // The last byte could be incomplete (i.e. not have 8 bits in + // it) but there is no problem since 0 XOR 0 == 0. + bits[i] ^= other.bits[i]; + } + } + + /** + * + * @param bitOffset first bit to start writing + * @param array array to write into. Bytes are written most-significant byte first. This is the opposite + * of the internal representation, which is exposed by {@link #getBitArray()} + * @param offset position in array to start writing + * @param numBytes how many bytes to write + */ + public void toBytes(int bitOffset, byte[] array, int offset, int numBytes) { + for (int i = 0; i < numBytes; i++) { + int theByte = 0; + for (int j = 0; j < 8; j++) { + if (get(bitOffset)) { + theByte |= 1 << (7 - j); + } + bitOffset++; + } + array[offset + i] = (byte) theByte; + } + } + + /** + * @return underlying array of ints. The first element holds the first 32 bits, and the least + * significant bit is bit 0. + */ + public int[] getBitArray() { + return bits; + } + + /** + * Reverses all bits in the array. + */ + public void reverse() { + int[] newBits = new int[bits.length]; + // reverse all int's first + int len = ((size-1) / 32); + int oldBitsLen = len + 1; + for (int i = 0; i < oldBitsLen; i++) { + long x = (long) bits[i]; + x = ((x >> 1) & 0x55555555L) | ((x & 0x55555555L) << 1); + x = ((x >> 2) & 0x33333333L) | ((x & 0x33333333L) << 2); + x = ((x >> 4) & 0x0f0f0f0fL) | ((x & 0x0f0f0f0fL) << 4); + x = ((x >> 8) & 0x00ff00ffL) | ((x & 0x00ff00ffL) << 8); + x = ((x >> 16) & 0x0000ffffL) | ((x & 0x0000ffffL) << 16); + newBits[len - i] = (int) x; + } + // now correct the int's if the bit size isn't a multiple of 32 + if (size != oldBitsLen * 32) { + int leftOffset = oldBitsLen * 32 - size; + int mask = 1; + for (int i = 0; i < 31 - leftOffset; i++) { + mask = (mask << 1) | 1; + } + int currentInt = (newBits[0] >> leftOffset) & mask; + for (int i = 1; i < oldBitsLen; i++) { + int nextInt = newBits[i]; + currentInt |= nextInt << (32 - leftOffset); + newBits[i - 1] = currentInt; + currentInt = (nextInt >> leftOffset) & mask; + } + newBits[oldBitsLen - 1] = currentInt; + } + bits = newBits; + } + + private static int[] makeArray(int size) { + return new int[(size + 31) / 32]; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof BitArray)) { + return false; + } + BitArray other = (BitArray) o; + return size == other.size && Arrays.equals(bits, other.bits); + } + + @Override + public int hashCode() { + return 31 * size + Arrays.hashCode(bits); + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(size); + for (int i = 0; i < size; i++) { + if ((i & 0x07) == 0) { + result.append(' '); + } + result.append(get(i) ? 'X' : '.'); + } + return result.toString(); + } + + @Override + public BitArray clone() { + return new BitArray(bits.clone(), size); + } + +} \ No newline at end of file diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/BitMatrix.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/BitMatrix.java new file mode 100644 index 000000000..30e2358cb --- /dev/null +++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/BitMatrix.java @@ -0,0 +1,449 @@ +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.common; + +import java.util.Arrays; + +/** + *Represents a 2D matrix of bits. In function arguments below, and throughout the common + * module, x is the column position, and y is the row position. The ordering is always x, y. + * The origin is at the top-left.
+ * + *Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins + * with a new int. This is done intentionally so that we can copy out a row into a BitArray very + * efficiently.
+ * + *The ordering of bits is row-major. Within each int, the least significant bits are used first, + * meaning they represent lower x values. This is compatible with BitArray's implementation.
+ * + * @author Sean Owen + * @author dswitkin@google.com (Daniel Switkin) + */ +public final class BitMatrix implements Cloneable { + + private final int width; + private final int height; + private final int rowSize; + private final int[] bits; + + // A helper to construct a square matrix. + public BitMatrix(int dimension) { + this(dimension, dimension); + } + + public BitMatrix(int width, int height) { + if (width < 1 || height < 1) { + throw new IllegalArgumentException("Both dimensions must be greater than 0"); + } + this.width = width; + this.height = height; + this.rowSize = (width + 31) / 32; + bits = new int[rowSize * height]; + } + + private BitMatrix(int width, int height, int rowSize, int[] bits) { + this.width = width; + this.height = height; + this.rowSize = rowSize; + this.bits = bits; + } + + public static BitMatrix parse(String stringRepresentation, String setString, String unsetString) { + if (stringRepresentation == null) { + throw new IllegalArgumentException(); + } + + boolean[] bits = new boolean[stringRepresentation.length()]; + int bitsPos = 0; + int rowStartPos = 0; + int rowLength = -1; + int nRows = 0; + int pos = 0; + while (pos < stringRepresentation.length()) { + if (stringRepresentation.charAt(pos) == '\n' || + stringRepresentation.charAt(pos) == '\r') { + if (bitsPos > rowStartPos) { + if (rowLength == -1) { + rowLength = bitsPos - rowStartPos; + } else if (bitsPos - rowStartPos != rowLength) { + throw new IllegalArgumentException("row lengths do not match"); + } + rowStartPos = bitsPos; + nRows++; + } + pos++; + } else if (stringRepresentation.substring(pos, pos + setString.length()).equals(setString)) { + pos += setString.length(); + bits[bitsPos] = true; + bitsPos++; + } else if (stringRepresentation.substring(pos, pos + unsetString.length()).equals(unsetString)) { + pos += unsetString.length(); + bits[bitsPos] = false; + bitsPos++; + } else { + throw new IllegalArgumentException( + "illegal character encountered: " + stringRepresentation.substring(pos)); + } + } + + // no EOL at end? + if (bitsPos > rowStartPos) { + if(rowLength == -1) { + rowLength = bitsPos - rowStartPos; + } else if (bitsPos - rowStartPos != rowLength) { + throw new IllegalArgumentException("row lengths do not match"); + } + nRows++; + } + + BitMatrix matrix = new BitMatrix(rowLength, nRows); + for (int i = 0; i < bitsPos; i++) { + if (bits[i]) { + matrix.set(i % rowLength, i / rowLength); + } + } + return matrix; + } + + /** + *Gets the requested bit, where true means black.
+ * + * @param x The horizontal component (i.e. which column) + * @param y The vertical component (i.e. which row) + * @return value of given bit in matrix + */ + public boolean get(int x, int y) { + int offset = y * rowSize + (x / 32); + return ((bits[offset] >>> (x & 0x1f)) & 1) != 0; + } + + /** + *Sets the given bit to true.
+ * + * @param x The horizontal component (i.e. which column) + * @param y The vertical component (i.e. which row) + */ + public void set(int x, int y) { + int offset = y * rowSize + (x / 32); + bits[offset] |= 1 << (x & 0x1f); + } + + public void unset(int x, int y) { + int offset = y * rowSize + (x / 32); + bits[offset] &= ~(1 << (x & 0x1f)); + } + + /** + *Flips the given bit.
+ * + * @param x The horizontal component (i.e. which column) + * @param y The vertical component (i.e. which row) + */ + public void flip(int x, int y) { + int offset = y * rowSize + (x / 32); + bits[offset] ^= 1 << (x & 0x1f); + } + + /** + * Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding + * mask bit is set. + * + * @param mask XOR mask + */ + public void xor(BitMatrix mask) { + if (width != mask.getWidth() || height != mask.getHeight() + || rowSize != mask.getRowSize()) { + throw new IllegalArgumentException("input matrix dimensions do not match"); + } + BitArray rowArray = new BitArray(width / 32 + 1); + for (int y = 0; y < height; y++) { + int offset = y * rowSize; + int[] row = mask.getRow(y, rowArray).getBitArray(); + for (int x = 0; x < rowSize; x++) { + bits[offset + x] ^= row[x]; + } + } + } + + /** + * Clears all bits (sets to false). + */ + public void clear() { + int max = bits.length; + for (int i = 0; i < max; i++) { + bits[i] = 0; + } + } + + /** + *Sets a square region of the bit matrix to true.
+ * + * @param left The horizontal position to begin at (inclusive) + * @param top The vertical position to begin at (inclusive) + * @param width The width of the region + * @param height The height of the region + */ + public void setRegion(int left, int top, int width, int height) { + if (top < 0 || left < 0) { + throw new IllegalArgumentException("Left and top must be nonnegative"); + } + if (height < 1 || width < 1) { + throw new IllegalArgumentException("Height and width must be at least 1"); + } + int right = left + width; + int bottom = top + height; + if (bottom > this.height || right > this.width) { + throw new IllegalArgumentException("The region must fit inside the matrix"); + } + for (int y = top; y < bottom; y++) { + int offset = y * rowSize; + for (int x = left; x < right; x++) { + bits[offset + (x / 32)] |= 1 << (x & 0x1f); + } + } + } + + /** + * A fast method to retrieve one row of data from the matrix as a BitArray. + * + * @param y The row to retrieve + * @param row An optional caller-allocated BitArray, will be allocated if null or too small + * @return The resulting BitArray - this reference should always be used even when passing + * your own row + */ + public BitArray getRow(int y, BitArray row) { + if (row == null || row.getSize() < width) { + row = new BitArray(width); + } else { + row.clear(); + } + int offset = y * rowSize; + for (int x = 0; x < rowSize; x++) { + row.setBulk(x * 32, bits[offset + x]); + } + return row; + } + + /** + * @param y row to set + * @param row {@link BitArray} to copy from + */ + public void setRow(int y, BitArray row) { + System.arraycopy(row.getBitArray(), 0, bits, y * rowSize, rowSize); + } + + /** + * Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees + */ + public void rotate180() { + int width = getWidth(); + int height = getHeight(); + BitArray topRow = new BitArray(width); + BitArray bottomRow = new BitArray(width); + for (int i = 0; i < (height+1) / 2; i++) { + topRow = getRow(i, topRow); + bottomRow = getRow(height - 1 - i, bottomRow); + topRow.reverse(); + bottomRow.reverse(); + setRow(i, bottomRow); + setRow(height - 1 - i, topRow); + } + } + + /** + * This is useful in detecting the enclosing rectangle of a 'pure' barcode. + * + * @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white + */ + public int[] getEnclosingRectangle() { + int left = width; + int top = height; + int right = -1; + int bottom = -1; + + for (int y = 0; y < height; y++) { + for (int x32 = 0; x32 < rowSize; x32++) { + int theBits = bits[y * rowSize + x32]; + if (theBits != 0) { + if (y < top) { + top = y; + } + if (y > bottom) { + bottom = y; + } + if (x32 * 32 < left) { + int bit = 0; + while ((theBits << (31 - bit)) == 0) { + bit++; + } + if ((x32 * 32 + bit) < left) { + left = x32 * 32 + bit; + } + } + if (x32 * 32 + 31 > right) { + int bit = 31; + while ((theBits >>> bit) == 0) { + bit--; + } + if ((x32 * 32 + bit) > right) { + right = x32 * 32 + bit; + } + } + } + } + } + + int width = right - left; + int height = bottom - top; + + if (width < 0 || height < 0) { + return null; + } + + return new int[] {left, top, width, height}; + } + + /** + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white + */ + public int[] getTopLeftOnBit() { + int bitsOffset = 0; + while (bitsOffset < bits.length && bits[bitsOffset] == 0) { + bitsOffset++; + } + if (bitsOffset == bits.length) { + return null; + } + int y = bitsOffset / rowSize; + int x = (bitsOffset % rowSize) * 32; + + int theBits = bits[bitsOffset]; + int bit = 0; + while ((theBits << (31-bit)) == 0) { + bit++; + } + x += bit; + return new int[] {x, y}; + } + + public int[] getBottomRightOnBit() { + int bitsOffset = bits.length - 1; + while (bitsOffset >= 0 && bits[bitsOffset] == 0) { + bitsOffset--; + } + if (bitsOffset < 0) { + return null; + } + + int y = bitsOffset / rowSize; + int x = (bitsOffset % rowSize) * 32; + + int theBits = bits[bitsOffset]; + int bit = 31; + while ((theBits >>> bit) == 0) { + bit--; + } + x += bit; + + return new int[] {x, y}; + } + + /** + * @return The width of the matrix + */ + public int getWidth() { + return width; + } + + /** + * @return The height of the matrix + */ + public int getHeight() { + return height; + } + + /** + * @return The row size of the matrix + */ + public int getRowSize() { + return rowSize; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof BitMatrix)) { + return false; + } + BitMatrix other = (BitMatrix) o; + return width == other.width && height == other.height && rowSize == other.rowSize && + Arrays.equals(bits, other.bits); + } + + @Override + public int hashCode() { + int hash = width; + hash = 31 * hash + width; + hash = 31 * hash + height; + hash = 31 * hash + rowSize; + hash = 31 * hash + Arrays.hashCode(bits); + return hash; + } + + /** + * @return string representation using "X" for set and " " for unset bits + */ + @Override + public String toString() { + return toString("X ", " "); + } + + /** + * @param setString representation of a set bit + * @param unsetString representation of an unset bit + * @return string representation of entire matrix utilizing given strings + */ + public String toString(String setString, String unsetString) { + return toString(setString, unsetString, "\n"); + } + + /** + * @param setString representation of a set bit + * @param unsetString representation of an unset bit + * @param lineSeparator newline character in string representation + * @return string representation of entire matrix utilizing given strings and line separator + * @deprecated call {@link #toString(String,String)} only, which uses \n line separator always + */ + @Deprecated + public String toString(String setString, String unsetString, String lineSeparator) { + StringBuilder result = new StringBuilder(height * (width + 1)); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + result.append(get(x, y) ? setString : unsetString); + } + result.append(lineSeparator); + } + return result.toString(); + } + + @Override + public BitMatrix clone() { + return new BitMatrix(width, height, rowSize, bits.clone()); + } + +} diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/CharacterSetECI.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/CharacterSetECI.java new file mode 100644 index 000000000..7c3853ca8 --- /dev/null +++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/CharacterSetECI.java @@ -0,0 +1,118 @@ +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.common; + +import com.google.zxing.FormatException; + +import java.util.HashMap; +import java.util.Map; + +/** + * Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1 + * of ISO 18004. + * + * @author Sean Owen + */ +public enum CharacterSetECI { + + // Enum name is a Java encoding valid for java.lang and java.io + Cp437(new int[]{0,2}), + ISO8859_1(new int[]{1,3}, "ISO-8859-1"), + ISO8859_2(4, "ISO-8859-2"), + ISO8859_3(5, "ISO-8859-3"), + ISO8859_4(6, "ISO-8859-4"), + ISO8859_5(7, "ISO-8859-5"), + ISO8859_6(8, "ISO-8859-6"), + ISO8859_7(9, "ISO-8859-7"), + ISO8859_8(10, "ISO-8859-8"), + ISO8859_9(11, "ISO-8859-9"), + ISO8859_10(12, "ISO-8859-10"), + ISO8859_11(13, "ISO-8859-11"), + ISO8859_13(15, "ISO-8859-13"), + ISO8859_14(16, "ISO-8859-14"), + ISO8859_15(17, "ISO-8859-15"), + ISO8859_16(18, "ISO-8859-16"), + SJIS(20, "Shift_JIS"), + Cp1250(21, "windows-1250"), + Cp1251(22, "windows-1251"), + Cp1252(23, "windows-1252"), + Cp1256(24, "windows-1256"), + UnicodeBigUnmarked(25, "UTF-16BE", "UnicodeBig"), + UTF8(26, "UTF-8"), + ASCII(new int[] {27, 170}, "US-ASCII"), + Big5(28), + GB18030(29, "GB2312", "EUC_CN", "GBK"), + EUC_KR(30, "EUC-KR"); + + private static final MapThis class contains utility methods for performing mathematical operations over + * the Galois Fields. Operations use a given primitive polynomial in calculations.
+ * + *Throughout this package, elements of the GF are represented as an {@code int} + * for convenience and speed (but at the cost of memory). + *
+ * + * @author Sean Owen + * @author David Olivier + */ +public final class GenericGF { + + public static final GenericGF AZTEC_DATA_12 = new GenericGF(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1 + public static final GenericGF AZTEC_DATA_10 = new GenericGF(0x409, 1024, 1); // x^10 + x^3 + 1 + public static final GenericGF AZTEC_DATA_6 = new GenericGF(0x43, 64, 1); // x^6 + x + 1 + public static final GenericGF AZTEC_PARAM = new GenericGF(0x13, 16, 1); // x^4 + x + 1 + public static final GenericGF QR_CODE_FIELD_256 = new GenericGF(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1 + public static final GenericGF DATA_MATRIX_FIELD_256 = new GenericGF(0x012D, 256, 1); // x^8 + x^5 + x^3 + x^2 + 1 + public static final GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256; + public static final GenericGF MAXICODE_FIELD_64 = AZTEC_DATA_6; + + private final int[] expTable; + private final int[] logTable; + private final GenericGFPoly zero; + private final GenericGFPoly one; + private final int size; + private final int primitive; + private final int generatorBase; + + /** + * Create a representation of GF(size) using the given primitive polynomial. + * + * @param primitive irreducible polynomial whose coefficients are represented by + * the bits of an int, where the least-significant bit represents the constant + * coefficient + * @param size the size of the field + * @param b the factor b in the generator polynomial can be 0- or 1-based + * (g(x) = (x+a^b)(x+a^(b+1))...(x+a^(b+2t-1))). + * In most cases it should be 1, but for QR code it is 0. + */ + public GenericGF(int primitive, int size, int b) { + this.primitive = primitive; + this.size = size; + this.generatorBase = b; + + expTable = new int[size]; + logTable = new int[size]; + int x = 1; + for (int i = 0; i < size; i++) { + expTable[i] = x; + x *= 2; // we're assuming the generator alpha is 2 + if (x >= size) { + x ^= primitive; + x &= size-1; + } + } + for (int i = 0; i < size-1; i++) { + logTable[expTable[i]] = i; + } + // logTable[0] == 0 but this should never be used + zero = new GenericGFPoly(this, new int[]{0}); + one = new GenericGFPoly(this, new int[]{1}); + } + + GenericGFPoly getZero() { + return zero; + } + + GenericGFPoly getOne() { + return one; + } + + /** + * @return the monomial representing coefficient * x^degree + */ + GenericGFPoly 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 GenericGFPoly(this, coefficients); + } + + /** + * Implements both addition and subtraction -- they are the same in GF(size). + * + * @return sum/difference of a and b + */ + static int addOrSubtract(int a, int b) { + return a ^ b; + } + + /** + * @return 2 to the power of a in GF(size) + */ + int exp(int a) { + return expTable[a]; + } + + /** + * @return base 2 log of a in GF(size) + */ + int log(int a) { + if (a == 0) { + throw new IllegalArgumentException(); + } + return logTable[a]; + } + + /** + * @return multiplicative inverse of a + */ + int inverse(int a) { + if (a == 0) { + throw new ArithmeticException(); + } + return expTable[size - logTable[a] - 1]; + } + + /** + * @return product of a and b in GF(size) + */ + int multiply(int a, int b) { + if (a == 0 || b == 0) { + return 0; + } + return expTable[(logTable[a] + logTable[b]) % (size - 1)]; + } + + public int getSize() { + return size; + } + + public int getGeneratorBase() { + return generatorBase; + } + + @Override + public String toString() { + return "GF(0x" + Integer.toHexString(primitive) + ',' + size + ')'; + } + +} diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/reedsolomon/GenericGFPoly.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/reedsolomon/GenericGFPoly.java new file mode 100644 index 000000000..8887e0ee1 --- /dev/null +++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/reedsolomon/GenericGFPoly.java @@ -0,0 +1,264 @@ +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.common.reedsolomon; + +/** + *Represents a polynomial whose coefficients are elements of a GF. + * Instances of this class are immutable.
+ * + *Much credit is due to William Rucklidge since portions of this code are an indirect + * port of his C++ Reed-Solomon implementation.
+ * + * @author Sean Owen + */ +final class GenericGFPoly { + + private final GenericGF field; + private final int[] coefficients; + + /** + * @param field the {@link GenericGF} instance representing the field to use + * to perform computations + * @param coefficients coefficients as ints representing elements of GF(size), 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") + */ + GenericGFPoly(GenericGF field, int[] coefficients) { + if (coefficients.length == 0) { + throw new IllegalArgumentException(); + } + this.field = field; + int coefficientsLength = coefficients.length; + if (coefficientsLength > 1 && coefficients[0] == 0) { + // Leading term must be non-zero for anything except the constant polynomial "0" + int firstNonZero = 1; + while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) { + firstNonZero++; + } + if (firstNonZero == coefficientsLength) { + this.coefficients = new int[]{0}; + } else { + this.coefficients = new int[coefficientsLength - firstNonZero]; + System.arraycopy(coefficients, + firstNonZero, + this.coefficients, + 0, + this.coefficients.length); + } + } else { + this.coefficients = coefficients; + } + } + + int[] getCoefficients() { + return 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 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); + } + int size = coefficients.length; + if (a == 1) { + // Just the sum of the coefficients + int result = 0; + for (int coefficient : coefficients) { + result = GenericGF.addOrSubtract(result, coefficient); + } + return result; + } + int result = coefficients[0]; + for (int i = 1; i < size; i++) { + result = GenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]); + } + return result; + } + + GenericGFPoly addOrSubtract(GenericGFPoly other) { + if (!field.equals(other.field)) { + throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field"); + } + 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] = GenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); + } + + return new GenericGFPoly(field, sumDiff); + } + + GenericGFPoly multiply(GenericGFPoly other) { + if (!field.equals(other.field)) { + throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field"); + } + if (isZero() || other.isZero()) { + return field.getZero(); + } + 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] = GenericGF.addOrSubtract(product[i + j], + field.multiply(aCoeff, bCoefficients[j])); + } + } + return new GenericGFPoly(field, product); + } + + GenericGFPoly multiply(int scalar) { + if (scalar == 0) { + return field.getZero(); + } + if (scalar == 1) { + return this; + } + int size = coefficients.length; + int[] product = new int[size]; + for (int i = 0; i < size; i++) { + product[i] = field.multiply(coefficients[i], scalar); + } + return new GenericGFPoly(field, product); + } + + GenericGFPoly multiplyByMonomial(int degree, int coefficient) { + if (degree < 0) { + throw new IllegalArgumentException(); + } + if (coefficient == 0) { + return field.getZero(); + } + int size = coefficients.length; + int[] product = new int[size + degree]; + for (int i = 0; i < size; i++) { + product[i] = field.multiply(coefficients[i], coefficient); + } + return new GenericGFPoly(field, product); + } + + GenericGFPoly[] divide(GenericGFPoly other) { + if (!field.equals(other.field)) { + throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field"); + } + if (other.isZero()) { + throw new IllegalArgumentException("Divide by 0"); + } + + GenericGFPoly quotient = field.getZero(); + GenericGFPoly remainder = this; + + int denominatorLeadingTerm = other.getCoefficient(other.getDegree()); + int inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm); + + while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) { + int degreeDifference = remainder.getDegree() - other.getDegree(); + int scale = field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm); + GenericGFPoly term = other.multiplyByMonomial(degreeDifference, scale); + GenericGFPoly iterationQuotient = field.buildMonomial(degreeDifference, scale); + quotient = quotient.addOrSubtract(iterationQuotient); + remainder = remainder.addOrSubtract(term); + } + + return new GenericGFPoly[] { quotient, remainder }; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(8 * getDegree()); + for (int degree = getDegree(); degree >= 0; degree--) { + int coefficient = getCoefficient(degree); + if (coefficient != 0) { + if (coefficient < 0) { + result.append(" - "); + coefficient = -coefficient; + } else { + if (result.length() > 0) { + result.append(" + "); + } + } + if (degree == 0 || coefficient != 1) { + int alphaPower = field.log(coefficient); + if (alphaPower == 0) { + result.append('1'); + } else if (alphaPower == 1) { + result.append('a'); + } else { + result.append("a^"); + result.append(alphaPower); + } + } + if (degree != 0) { + if (degree == 1) { + result.append('x'); + } else { + result.append("x^"); + result.append(degree); + } + } + } + } + return result.toString(); + } + +} diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java new file mode 100644 index 000000000..ff813cb1f --- /dev/null +++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java @@ -0,0 +1,74 @@ +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.common.reedsolomon; + +import java.util.ArrayList; +import java.util.List; + +/** + *Implements Reed-Solomon enbcoding, as the name implies.
+ * + * @author Sean Owen + * @author William Rucklidge + */ +public final class ReedSolomonEncoder { + + private final GenericGF field; + private final ListSee ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels + * defined by the QR code standard.
+ * + * @author Sean Owen + */ +public enum ErrorCorrectionLevel { + + /** L = ~7% correction */ + L(0x01), + /** M = ~15% correction */ + M(0x00), + /** Q = ~25% correction */ + Q(0x03), + /** H = ~30% correction */ + H(0x02); + + private static final ErrorCorrectionLevel[] FOR_BITS = {M, L, H, Q}; + + private final int bits; + + ErrorCorrectionLevel(int bits) { + this.bits = bits; + } + + public int getBits() { + return bits; + } + + /** + * @param bits int containing the two bits encoding a QR Code's error correction level + * @return ErrorCorrectionLevel representing the encoded error correction level + */ + public static ErrorCorrectionLevel forBits(int bits) { + if (bits < 0 || bits >= FOR_BITS.length) { + throw new IllegalArgumentException(); + } + return FOR_BITS[bits]; + } + + +} diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/decoder/FormatInformation.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/decoder/FormatInformation.java new file mode 100644 index 000000000..894e32175 --- /dev/null +++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/decoder/FormatInformation.java @@ -0,0 +1,172 @@ +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.qrcode.decoder; + +/** + *Encapsulates a QR Code's format information, including the data mask used and + * error correction level.
+ * + * @author Sean Owen + * @see DataMask + * @see ErrorCorrectionLevel + */ +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 = { + {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}, + }; + + /** + * Offset i holds the number of 1 bits in the binary representation of i + */ + private static final int[] BITS_SET_IN_HALF_BYTE = + {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; // a now has a 1 bit exactly where its bit differs with b's + // Count bits set quickly with a series of lookups: + 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)]; + } + + /** + * @param maskedFormatInfo1 format info indicator, with mask still applied + * @param maskedFormatInfo2 second copy of same info; both are checked at the same time + * to establish best match + * @return information about the format it specifies, or {@code null} + * if doesn't seem to match any known pattern + */ + static FormatInformation decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) { + FormatInformation formatInfo = doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2); + if (formatInfo != null) { + return formatInfo; + } + // Should return null, but, some QR codes apparently + // do not mask this info. Try again by actually masking the pattern + // first + return doDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR, + maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR); + } + + private static FormatInformation doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) { + // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing + int bestDifference = Integer.MAX_VALUE; + int bestFormatInfo = 0; + for (int[] decodeInfo : FORMAT_INFO_DECODE_LOOKUP) { + int targetInfo = decodeInfo[0]; + if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2) { + // Found an exact match + return new FormatInformation(decodeInfo[1]); + } + int bitsDifference = numBitsDiffering(maskedFormatInfo1, targetInfo); + if (bitsDifference < bestDifference) { + bestFormatInfo = decodeInfo[1]; + bestDifference = bitsDifference; + } + if (maskedFormatInfo1 != maskedFormatInfo2) { + // also try the other option + bitsDifference = numBitsDiffering(maskedFormatInfo2, targetInfo); + if (bitsDifference < bestDifference) { + bestFormatInfo = decodeInfo[1]; + bestDifference = bitsDifference; + } + } + } + // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits + // differing means we found a match + if (bestDifference <= 3) { + return new FormatInformation(bestFormatInfo); + } + return null; + } + + ErrorCorrectionLevel getErrorCorrectionLevel() { + return errorCorrectionLevel; + } + + byte getDataMask() { + return dataMask; + } + + @Override + public int hashCode() { + return (errorCorrectionLevel.ordinal() << 3) | (int) dataMask; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof FormatInformation)) { + return false; + } + FormatInformation other = (FormatInformation) o; + return this.errorCorrectionLevel == other.errorCorrectionLevel && + this.dataMask == other.dataMask; + } + +} diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/decoder/Mode.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/decoder/Mode.java new file mode 100644 index 000000000..b7e9ab3a9 --- /dev/null +++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/decoder/Mode.java @@ -0,0 +1,102 @@ +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.qrcode.decoder; + +/** + *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.
+ * + * @author Sean Owen + */ +public enum Mode { + + TERMINATOR(new int[]{0, 0, 0}, 0x00), // Not really a mode... + NUMERIC(new int[]{10, 12, 14}, 0x01), + ALPHANUMERIC(new int[]{9, 11, 13}, 0x02), + STRUCTURED_APPEND(new int[]{0, 0, 0}, 0x03), // Not supported + BYTE(new int[]{8, 16, 16}, 0x04), + ECI(new int[]{0, 0, 0}, 0x07), // character counts don't apply + KANJI(new int[]{8, 10, 12}, 0x08), + FNC1_FIRST_POSITION(new int[]{0, 0, 0}, 0x05), + FNC1_SECOND_POSITION(new int[]{0, 0, 0}, 0x09), + /** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */ + HANZI(new int[]{8, 10, 12}, 0x0D); + + private final int[] characterCountBitsForVersions; + private final int bits; + + Mode(int[] characterCountBitsForVersions, int bits) { + this.characterCountBitsForVersions = characterCountBitsForVersions; + this.bits = bits; + } + + /** + * @param bits four bits encoding a QR Code data mode + * @return Mode encoded by these bits + * @throws IllegalArgumentException if bits do not correspond to a known mode + */ + public static Mode forBits(int bits) { + switch (bits) { + case 0x0: + return TERMINATOR; + case 0x1: + return NUMERIC; + case 0x2: + return ALPHANUMERIC; + case 0x3: + return STRUCTURED_APPEND; + case 0x4: + return BYTE; + case 0x5: + return FNC1_FIRST_POSITION; + case 0x7: + return ECI; + case 0x8: + return KANJI; + case 0x9: + return FNC1_SECOND_POSITION; + case 0xD: + // 0xD is defined in GBT 18284-2000, may not be supported in foreign country + return HANZI; + default: + throw new IllegalArgumentException(); + } + } + + /** + * @param version version in question + * @return number of bits used, in this QR Code symbol {@link Version}, to encode the + * count of characters that will follow encoded in this Mode + */ + public 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]; + } + + public int getBits() { + return bits; + } + +} diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/decoder/Version.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/decoder/Version.java new file mode 100644 index 000000000..cc4052508 --- /dev/null +++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/decoder/Version.java @@ -0,0 +1,578 @@ +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.qrcode.decoder; + +import com.google.zxing.FormatException; +import com.google.zxing.common.BitMatrix; + +/** + * See ISO 18004:2006 Annex D + * + * @author Sean Owen + */ +public final class Version { + + /** + * See ISO 18004:2006 Annex D. + * Element i represents the raw version bits that specify version i + 7 + */ + private static final int[] VERSION_DECODE_INFO = { + 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, + 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, + 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, + 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, + 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, + 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, + 0x2542E, 0x26A64, 0x27541, 0x28C69 + }; + + private static final Version[] VERSIONS = buildVersions(); + + private final int versionNumber; + private final int[] alignmentPatternCenters; + private final ECBlocks[] ecBlocks; + private final int totalCodewords; + + private Version(int versionNumber, + int[] alignmentPatternCenters, + ECBlocks... ecBlocks) { + this.versionNumber = versionNumber; + this.alignmentPatternCenters = alignmentPatternCenters; + this.ecBlocks = ecBlocks; + int total = 0; + int ecCodewords = ecBlocks[0].getECCodewordsPerBlock(); + ECB[] ecbArray = ecBlocks[0].getECBlocks(); + for (ECB ecBlock : ecbArray) { + total += ecBlock.getCount() * (ecBlock.getDataCodewords() + ecCodewords); + } + this.totalCodewords = total; + } + + public int getVersionNumber() { + return versionNumber; + } + + public int[] getAlignmentPatternCenters() { + return alignmentPatternCenters; + } + + public int getTotalCodewords() { + return totalCodewords; + } + + public int getDimensionForVersion() { + return 17 + 4 * versionNumber; + } + + public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) { + return ecBlocks[ecLevel.ordinal()]; + } + + /** + *Deduces version information purely from QR Code dimensions.
+ * + * @param dimension dimension in modules + * @return Version for a QR Code of that dimension + * @throws FormatException if dimension is not 1 mod 4 + */ + public static Version getProvisionalVersionForDimension(int dimension) throws FormatException { + if (dimension % 4 != 1) { + throw FormatException.getFormatInstance(); + } + try { + return getVersionForNumber((dimension - 17) / 4); + } catch (IllegalArgumentException ignored) { + throw FormatException.getFormatInstance(); + } + } + + public static Version getVersionForNumber(int versionNumber) { + if (versionNumber < 1 || versionNumber > 40) { + throw new IllegalArgumentException(); + } + return VERSIONS[versionNumber - 1]; + } + + static Version decodeVersionInformation(int versionBits) { + int bestDifference = Integer.MAX_VALUE; + int bestVersion = 0; + for (int i = 0; i < VERSION_DECODE_INFO.length; i++) { + int targetVersion = VERSION_DECODE_INFO[i]; + // Do the version info bits match exactly? done. + if (targetVersion == versionBits) { + return getVersionForNumber(i + 7); + } + // Otherwise see if this is the closest to a real version info bit string + // we have seen so far + int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion); + if (bitsDifference < bestDifference) { + bestVersion = i + 7; + bestDifference = bitsDifference; + } + } + // We can tolerate up to 3 bits of error since no two version info codewords will + // differ in less than 8 bits. + if (bestDifference <= 3) { + return getVersionForNumber(bestVersion); + } + // If we didn't find a close enough match, fail + return null; + } + + /** + * See ISO 18004:2006 Annex E + */ + BitMatrix buildFunctionPattern() { + int dimension = getDimensionForVersion(); + BitMatrix bitMatrix = new BitMatrix(dimension); + + // Top left finder pattern + separator + format + bitMatrix.setRegion(0, 0, 9, 9); + // Top right finder pattern + separator + format + bitMatrix.setRegion(dimension - 8, 0, 8, 9); + // Bottom left finder pattern + separator + format + bitMatrix.setRegion(0, dimension - 8, 9, 8); + + // Alignment patterns + int max = alignmentPatternCenters.length; + for (int x = 0; x < max; x++) { + int i = alignmentPatternCenters[x] - 2; + for (int y = 0; y < max; y++) { + if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) { + // No alignment patterns near the three finder paterns + continue; + } + bitMatrix.setRegion(alignmentPatternCenters[y] - 2, i, 5, 5); + } + } + + // Vertical timing pattern + bitMatrix.setRegion(6, 9, 1, dimension - 17); + // Horizontal timing pattern + bitMatrix.setRegion(9, 6, dimension - 17, 1); + + if (versionNumber > 6) { + // Version info, top right + bitMatrix.setRegion(dimension - 11, 0, 3, 6); + // Version info, bottom left + bitMatrix.setRegion(0, dimension - 11, 6, 3); + } + + return bitMatrix; + } + + /** + *Encapsulates a set of error-correction blocks in one symbol version. Most versions will + * use blocks of differing sizes within one version, so, this encapsulates the parameters for + * each set of blocks. It also holds the number of error-correction codewords per block since it + * will be the same across all blocks within one version.
+ */ + public static final class ECBlocks { + private final int ecCodewordsPerBlock; + private final ECB[] ecBlocks; + + ECBlocks(int ecCodewordsPerBlock, ECB... ecBlocks) { + this.ecCodewordsPerBlock = ecCodewordsPerBlock; + this.ecBlocks = ecBlocks; + } + + public int getECCodewordsPerBlock() { + return ecCodewordsPerBlock; + } + + public int getNumBlocks() { + int total = 0; + for (ECB ecBlock : ecBlocks) { + total += ecBlock.getCount(); + } + return total; + } + + public int getTotalECCodewords() { + return ecCodewordsPerBlock * getNumBlocks(); + } + + public ECB[] getECBlocks() { + return ecBlocks; + } + } + + /** + *Encapsualtes the parameters for one error-correction block in one symbol version. + * This includes the number of data codewords, and the number of times a block with these + * parameters is used consecutively in the QR code version's format.
+ */ + public static final class ECB { + private final int count; + private final int dataCodewords; + + ECB(int count, int dataCodewords) { + this.count = count; + this.dataCodewords = dataCodewords; + } + + public int getCount() { + return count; + } + + public int getDataCodewords() { + return dataCodewords; + } + } + + @Override + public String toString() { + return String.valueOf(versionNumber); + } + + /** + * See ISO 18004:2006 6.5.1 Table 9 + */ + private static Version[] buildVersions() { + return new Version[]{ + new Version(1, new int[]{}, + new ECBlocks(7, new ECB(1, 19)), + new ECBlocks(10, new ECB(1, 16)), + new ECBlocks(13, new ECB(1, 13)), + new ECBlocks(17, new ECB(1, 9))), + new Version(2, new int[]{6, 18}, + new ECBlocks(10, new ECB(1, 34)), + new ECBlocks(16, new ECB(1, 28)), + new ECBlocks(22, new ECB(1, 22)), + new ECBlocks(28, new ECB(1, 16))), + new Version(3, new int[]{6, 22}, + new ECBlocks(15, new ECB(1, 55)), + new ECBlocks(26, new ECB(1, 44)), + new ECBlocks(18, new ECB(2, 17)), + new ECBlocks(22, new ECB(2, 13))), + new Version(4, new int[]{6, 26}, + new ECBlocks(20, new ECB(1, 80)), + new ECBlocks(18, new ECB(2, 32)), + new ECBlocks(26, new ECB(2, 24)), + new ECBlocks(16, new ECB(4, 9))), + new Version(5, new int[]{6, 30}, + new ECBlocks(26, new ECB(1, 108)), + new ECBlocks(24, new ECB(2, 43)), + new ECBlocks(18, new ECB(2, 15), + new ECB(2, 16)), + new ECBlocks(22, new ECB(2, 11), + new ECB(2, 12))), + new Version(6, new int[]{6, 34}, + new ECBlocks(18, new ECB(2, 68)), + new ECBlocks(16, new ECB(4, 27)), + new ECBlocks(24, new ECB(4, 19)), + new ECBlocks(28, new ECB(4, 15))), + new Version(7, new int[]{6, 22, 38}, + new ECBlocks(20, new ECB(2, 78)), + new ECBlocks(18, new ECB(4, 31)), + new ECBlocks(18, new ECB(2, 14), + new ECB(4, 15)), + new ECBlocks(26, new ECB(4, 13), + new ECB(1, 14))), + new Version(8, new int[]{6, 24, 42}, + new ECBlocks(24, new ECB(2, 97)), + new ECBlocks(22, new ECB(2, 38), + new ECB(2, 39)), + new ECBlocks(22, new ECB(4, 18), + new ECB(2, 19)), + new ECBlocks(26, new ECB(4, 14), + new ECB(2, 15))), + new Version(9, new int[]{6, 26, 46}, + new ECBlocks(30, new ECB(2, 116)), + new ECBlocks(22, new ECB(3, 36), + new ECB(2, 37)), + new ECBlocks(20, new ECB(4, 16), + new ECB(4, 17)), + new ECBlocks(24, new ECB(4, 12), + new ECB(4, 13))), + new Version(10, new int[]{6, 28, 50}, + new ECBlocks(18, new ECB(2, 68), + new ECB(2, 69)), + new ECBlocks(26, new ECB(4, 43), + new ECB(1, 44)), + new ECBlocks(24, new ECB(6, 19), + new ECB(2, 20)), + new ECBlocks(28, new ECB(6, 15), + new ECB(2, 16))), + new Version(11, new int[]{6, 30, 54}, + new ECBlocks(20, new ECB(4, 81)), + new ECBlocks(30, new ECB(1, 50), + new ECB(4, 51)), + new ECBlocks(28, new ECB(4, 22), + new ECB(4, 23)), + new ECBlocks(24, new ECB(3, 12), + new ECB(8, 13))), + new Version(12, new int[]{6, 32, 58}, + new ECBlocks(24, new ECB(2, 92), + new ECB(2, 93)), + new ECBlocks(22, new ECB(6, 36), + new ECB(2, 37)), + new ECBlocks(26, new ECB(4, 20), + new ECB(6, 21)), + new ECBlocks(28, new ECB(7, 14), + new ECB(4, 15))), + new Version(13, new int[]{6, 34, 62}, + new ECBlocks(26, new ECB(4, 107)), + new ECBlocks(22, new ECB(8, 37), + new ECB(1, 38)), + new ECBlocks(24, new ECB(8, 20), + new ECB(4, 21)), + new ECBlocks(22, new ECB(12, 11), + new ECB(4, 12))), + new Version(14, new int[]{6, 26, 46, 66}, + new ECBlocks(30, new ECB(3, 115), + new ECB(1, 116)), + new ECBlocks(24, new ECB(4, 40), + new ECB(5, 41)), + new ECBlocks(20, new ECB(11, 16), + new ECB(5, 17)), + new ECBlocks(24, new ECB(11, 12), + new ECB(5, 13))), + new Version(15, new int[]{6, 26, 48, 70}, + new ECBlocks(22, new ECB(5, 87), + new ECB(1, 88)), + new ECBlocks(24, new ECB(5, 41), + new ECB(5, 42)), + new ECBlocks(30, new ECB(5, 24), + new ECB(7, 25)), + new ECBlocks(24, new ECB(11, 12), + new ECB(7, 13))), + new Version(16, new int[]{6, 26, 50, 74}, + new ECBlocks(24, new ECB(5, 98), + new ECB(1, 99)), + new ECBlocks(28, new ECB(7, 45), + new ECB(3, 46)), + new ECBlocks(24, new ECB(15, 19), + new ECB(2, 20)), + new ECBlocks(30, new ECB(3, 15), + new ECB(13, 16))), + new Version(17, new int[]{6, 30, 54, 78}, + new ECBlocks(28, new ECB(1, 107), + new ECB(5, 108)), + new ECBlocks(28, new ECB(10, 46), + new ECB(1, 47)), + new ECBlocks(28, new ECB(1, 22), + new ECB(15, 23)), + new ECBlocks(28, new ECB(2, 14), + new ECB(17, 15))), + new Version(18, new int[]{6, 30, 56, 82}, + new ECBlocks(30, new ECB(5, 120), + new ECB(1, 121)), + new ECBlocks(26, new ECB(9, 43), + new ECB(4, 44)), + new ECBlocks(28, new ECB(17, 22), + new ECB(1, 23)), + new ECBlocks(28, new ECB(2, 14), + new ECB(19, 15))), + new Version(19, new int[]{6, 30, 58, 86}, + new ECBlocks(28, new ECB(3, 113), + new ECB(4, 114)), + new ECBlocks(26, new ECB(3, 44), + new ECB(11, 45)), + new ECBlocks(26, new ECB(17, 21), + new ECB(4, 22)), + new ECBlocks(26, new ECB(9, 13), + new ECB(16, 14))), + new Version(20, new int[]{6, 34, 62, 90}, + new ECBlocks(28, new ECB(3, 107), + new ECB(5, 108)), + new ECBlocks(26, new ECB(3, 41), + new ECB(13, 42)), + new ECBlocks(30, new ECB(15, 24), + new ECB(5, 25)), + new ECBlocks(28, new ECB(15, 15), + new ECB(10, 16))), + new Version(21, new int[]{6, 28, 50, 72, 94}, + new ECBlocks(28, new ECB(4, 116), + new ECB(4, 117)), + new ECBlocks(26, new ECB(17, 42)), + new ECBlocks(28, new ECB(17, 22), + new ECB(6, 23)), + new ECBlocks(30, new ECB(19, 16), + new ECB(6, 17))), + new Version(22, new int[]{6, 26, 50, 74, 98}, + new ECBlocks(28, new ECB(2, 111), + new ECB(7, 112)), + new ECBlocks(28, new ECB(17, 46)), + new ECBlocks(30, new ECB(7, 24), + new ECB(16, 25)), + new ECBlocks(24, new ECB(34, 13))), + new Version(23, new int[]{6, 30, 54, 78, 102}, + new ECBlocks(30, new ECB(4, 121), + new ECB(5, 122)), + new ECBlocks(28, new ECB(4, 47), + new ECB(14, 48)), + new ECBlocks(30, new ECB(11, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(16, 15), + new ECB(14, 16))), + new Version(24, new int[]{6, 28, 54, 80, 106}, + new ECBlocks(30, new ECB(6, 117), + new ECB(4, 118)), + new ECBlocks(28, new ECB(6, 45), + new ECB(14, 46)), + new ECBlocks(30, new ECB(11, 24), + new ECB(16, 25)), + new ECBlocks(30, new ECB(30, 16), + new ECB(2, 17))), + new Version(25, new int[]{6, 32, 58, 84, 110}, + new ECBlocks(26, new ECB(8, 106), + new ECB(4, 107)), + new ECBlocks(28, new ECB(8, 47), + new ECB(13, 48)), + new ECBlocks(30, new ECB(7, 24), + new ECB(22, 25)), + new ECBlocks(30, new ECB(22, 15), + new ECB(13, 16))), + new Version(26, new int[]{6, 30, 58, 86, 114}, + new ECBlocks(28, new ECB(10, 114), + new ECB(2, 115)), + new ECBlocks(28, new ECB(19, 46), + new ECB(4, 47)), + new ECBlocks(28, new ECB(28, 22), + new ECB(6, 23)), + new ECBlocks(30, new ECB(33, 16), + new ECB(4, 17))), + new Version(27, new int[]{6, 34, 62, 90, 118}, + new ECBlocks(30, new ECB(8, 122), + new ECB(4, 123)), + new ECBlocks(28, new ECB(22, 45), + new ECB(3, 46)), + new ECBlocks(30, new ECB(8, 23), + new ECB(26, 24)), + new ECBlocks(30, new ECB(12, 15), + new ECB(28, 16))), + new Version(28, new int[]{6, 26, 50, 74, 98, 122}, + new ECBlocks(30, new ECB(3, 117), + new ECB(10, 118)), + new ECBlocks(28, new ECB(3, 45), + new ECB(23, 46)), + new ECBlocks(30, new ECB(4, 24), + new ECB(31, 25)), + new ECBlocks(30, new ECB(11, 15), + new ECB(31, 16))), + new Version(29, new int[]{6, 30, 54, 78, 102, 126}, + new ECBlocks(30, new ECB(7, 116), + new ECB(7, 117)), + new ECBlocks(28, new ECB(21, 45), + new ECB(7, 46)), + new ECBlocks(30, new ECB(1, 23), + new ECB(37, 24)), + new ECBlocks(30, new ECB(19, 15), + new ECB(26, 16))), + new Version(30, new int[]{6, 26, 52, 78, 104, 130}, + new ECBlocks(30, new ECB(5, 115), + new ECB(10, 116)), + new ECBlocks(28, new ECB(19, 47), + new ECB(10, 48)), + new ECBlocks(30, new ECB(15, 24), + new ECB(25, 25)), + new ECBlocks(30, new ECB(23, 15), + new ECB(25, 16))), + new Version(31, new int[]{6, 30, 56, 82, 108, 134}, + new ECBlocks(30, new ECB(13, 115), + new ECB(3, 116)), + new ECBlocks(28, new ECB(2, 46), + new ECB(29, 47)), + new ECBlocks(30, new ECB(42, 24), + new ECB(1, 25)), + new ECBlocks(30, new ECB(23, 15), + new ECB(28, 16))), + new Version(32, new int[]{6, 34, 60, 86, 112, 138}, + new ECBlocks(30, new ECB(17, 115)), + new ECBlocks(28, new ECB(10, 46), + new ECB(23, 47)), + new ECBlocks(30, new ECB(10, 24), + new ECB(35, 25)), + new ECBlocks(30, new ECB(19, 15), + new ECB(35, 16))), + new Version(33, new int[]{6, 30, 58, 86, 114, 142}, + new ECBlocks(30, new ECB(17, 115), + new ECB(1, 116)), + new ECBlocks(28, new ECB(14, 46), + new ECB(21, 47)), + new ECBlocks(30, new ECB(29, 24), + new ECB(19, 25)), + new ECBlocks(30, new ECB(11, 15), + new ECB(46, 16))), + new Version(34, new int[]{6, 34, 62, 90, 118, 146}, + new ECBlocks(30, new ECB(13, 115), + new ECB(6, 116)), + new ECBlocks(28, new ECB(14, 46), + new ECB(23, 47)), + new ECBlocks(30, new ECB(44, 24), + new ECB(7, 25)), + new ECBlocks(30, new ECB(59, 16), + new ECB(1, 17))), + new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150}, + new ECBlocks(30, new ECB(12, 121), + new ECB(7, 122)), + new ECBlocks(28, new ECB(12, 47), + new ECB(26, 48)), + new ECBlocks(30, new ECB(39, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(22, 15), + new ECB(41, 16))), + new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154}, + new ECBlocks(30, new ECB(6, 121), + new ECB(14, 122)), + new ECBlocks(28, new ECB(6, 47), + new ECB(34, 48)), + new ECBlocks(30, new ECB(46, 24), + new ECB(10, 25)), + new ECBlocks(30, new ECB(2, 15), + new ECB(64, 16))), + new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158}, + new ECBlocks(30, new ECB(17, 122), + new ECB(4, 123)), + new ECBlocks(28, new ECB(29, 46), + new ECB(14, 47)), + new ECBlocks(30, new ECB(49, 24), + new ECB(10, 25)), + new ECBlocks(30, new ECB(24, 15), + new ECB(46, 16))), + new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162}, + new ECBlocks(30, new ECB(4, 122), + new ECB(18, 123)), + new ECBlocks(28, new ECB(13, 46), + new ECB(32, 47)), + new ECBlocks(30, new ECB(48, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(42, 15), + new ECB(32, 16))), + new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166}, + new ECBlocks(30, new ECB(20, 117), + new ECB(4, 118)), + new ECBlocks(28, new ECB(40, 47), + new ECB(7, 48)), + new ECBlocks(30, new ECB(43, 24), + new ECB(22, 25)), + new ECBlocks(30, new ECB(10, 15), + new ECB(67, 16))), + new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170}, + new ECBlocks(30, new ECB(19, 118), + new ECB(6, 119)), + new ECBlocks(28, new ECB(18, 47), + new ECB(31, 48)), + new ECBlocks(30, new ECB(34, 24), + new ECB(34, 25)), + new ECBlocks(30, new ECB(20, 15), + new ECB(61, 16))) + }; + } + +} diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/encoder/BlockPair.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/encoder/BlockPair.java new file mode 100644 index 000000000..5714d9c3a --- /dev/null +++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/encoder/BlockPair.java @@ -0,0 +1,37 @@ +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.qrcode.encoder; + +final class BlockPair { + + private final byte[] dataBytes; + private final byte[] errorCorrectionBytes; + + BlockPair(byte[] data, byte[] errorCorrection) { + dataBytes = data; + errorCorrectionBytes = errorCorrection; + } + + public byte[] getDataBytes() { + return dataBytes; + } + + public byte[] getErrorCorrectionBytes() { + return errorCorrectionBytes; + } + +} diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/encoder/ByteMatrix.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/encoder/ByteMatrix.java new file mode 100644 index 000000000..d7fef0601 --- /dev/null +++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/encoder/ByteMatrix.java @@ -0,0 +1,98 @@ +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.qrcode.encoder; + +/** + * JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned + * -1, 0, and 1, I'm going to use less memory and go with bytes. + * + * @author dswitkin@google.com (Daniel Switkin) + */ +public final class ByteMatrix { + + private final byte[][] bytes; + private final int width; + private final int height; + + public ByteMatrix(int width, int height) { + bytes = new byte[height][width]; + this.width = width; + this.height = height; + } + + public int getHeight() { + return height; + } + + public int getWidth() { + return width; + } + + public byte get(int x, int y) { + return bytes[y][x]; + } + + /** + * @return an internal representation as bytes, in row-major order. array[y][x] represents point (x,y) + */ + public byte[][] getArray() { + return bytes; + } + + public void set(int x, int y, byte value) { + bytes[y][x] = value; + } + + public void set(int x, int y, int value) { + bytes[y][x] = (byte) value; + } + + public void set(int x, int y, boolean value) { + bytes[y][x] = (byte) (value ? 1 : 0); + } + + public void clear(byte value) { + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + bytes[y][x] = value; + } + } + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(2 * width * height + 2); + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + switch (bytes[y][x]) { + case 0: + result.append(" 0"); + break; + case 1: + result.append(" 1"); + break; + default: + result.append(" "); + break; + } + } + result.append('\n'); + } + return result.toString(); + } + +} diff --git a/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/encoder/Encoder.java b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/encoder/Encoder.java new file mode 100644 index 000000000..013b1fa2d --- /dev/null +++ b/apps/imagegen/zxing/core/src/main/java/com/google/zxing/qrcode/encoder/Encoder.java @@ -0,0 +1,578 @@ +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.zxing.qrcode.encoder; + +import com.google.zxing.EncodeHintType; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitArray; +import com.google.zxing.common.CharacterSetECI; +import com.google.zxing.common.reedsolomon.GenericGF; +import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import com.google.zxing.qrcode.decoder.Mode; +import com.google.zxing.qrcode.decoder.Version; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +/** + * @author satorux@google.com (Satoru Takabayashi) - creator + * @author dswitkin@google.com (Daniel Switkin) - ported from C++ + */ +public final class Encoder { + + // The original table is defined in the table 5 of JISX0510:2004 (p.19). + private static final int[] ALPHANUMERIC_TABLE = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f + 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f + }; + + static final String DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1"; + + private Encoder() { + } + + // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. + // Basically it applies four rules and summate all penalties. + private static int calculateMaskPenalty(ByteMatrix matrix) { + return MaskUtil.applyMaskPenaltyRule1(matrix) + + MaskUtil.applyMaskPenaltyRule2(matrix) + + MaskUtil.applyMaskPenaltyRule3(matrix) + + MaskUtil.applyMaskPenaltyRule4(matrix); + } + + /** + * @param content text to encode + * @param ecLevel error correction level to use + * @return {@link QRCode} representing the encoded QR code + * @throws WriterException if encoding can't succeed, because of for example invalid content + * or configuration + */ + public static QRCode encode(String content, ErrorCorrectionLevel ecLevel) throws WriterException { + return encode(content, ecLevel, null); + } + + public static QRCode encode(String content, + ErrorCorrectionLevel ecLevel, + Map