diff --git a/src/io/nayuki/fastqrcodegen/BitBuffer.java b/src/io/nayuki/fastqrcodegen/BitBuffer.java index 630ad5b..a2d573e 100644 --- a/src/io/nayuki/fastqrcodegen/BitBuffer.java +++ b/src/io/nayuki/fastqrcodegen/BitBuffer.java @@ -27,6 +27,9 @@ import java.util.Arrays; import java.util.Objects; +/** + * An appendable sequence of bits (0s and 1s). Mainly used by {@link QrSegment}. + */ final class BitBuffer { /*---- Fields ----*/ @@ -39,6 +42,9 @@ final class BitBuffer { /*---- Constructor ----*/ + /** + * Constructs an empty bit buffer (length 0). + */ public BitBuffer() { data = new int[64]; bitLength = 0; @@ -48,6 +54,10 @@ final class BitBuffer { /*---- Methods ----*/ + /** + * Returns the length of this sequence, which is a non-negative value. + * @return the length of this sequence + */ public int getBit(int index) { if (index < 0 || index >= bitLength) throw new IndexOutOfBoundsException(); @@ -65,6 +75,15 @@ final class BitBuffer { } + /** + * Appends the specified number of low-order bits of the specified value to this + * buffer. Requires 0 ≤ len ≤ 31 and 0 ≤ val < 2len. + * @param val the value to append + * @param len the number of low-order bits in the value to take + * @throws IllegalArgumentException if the value or number of bits is out of range + * @throws IllegalStateException if appending the data + * would make bitLength exceed Integer.MAX_VALUE + */ public void appendBits(int val, int len) { if (len < 0 || len > 31 || val >>> len != 0) throw new IllegalArgumentException("Value out of range"); diff --git a/src/io/nayuki/fastqrcodegen/QrCode.java b/src/io/nayuki/fastqrcodegen/QrCode.java index ea295f4..42fdaec 100644 --- a/src/io/nayuki/fastqrcodegen/QrCode.java +++ b/src/io/nayuki/fastqrcodegen/QrCode.java @@ -29,10 +29,44 @@ import java.util.List; import java.util.Objects; +/** + * A QR Code symbol, which is a type of two-dimension barcode. + * Invented by Denso Wave and described in the ISO/IEC 18004 standard. + *
Instances of this class represent an immutable square grid of black and white cells. + * The class provides static factory functions to create a QR Code from text or binary data. + * The class covers the QR Code Model 2 specification, supporting all versions (sizes) + * from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
+ *Ways to create a QR Code object:
+ *High level: Take the payload data and call {@link QrCode#encodeText(String,Ecc)} + * or {@link QrCode#encodeBinary(byte[],Ecc)}.
Mid level: Custom-make the list of {@link QrSegment segments} + * and call {@link QrCode#encodeSegments(List,Ecc)} or + * {@link QrCode#encodeSegments(List,Ecc,int,int,int,boolean)}
Low level: Custom-make the array of data codeword bytes (including segment headers and + * final padding, excluding error correction codewords), supply the appropriate version number, + * and call the {@link QrCode#QrCode(int,Ecc,byte[],int) constructor}.
(Note that all ways require supplying the desired error correction level.)
+ * @see QrSegment + */ public final class QrCode { - /*---- Public static factory functions ----*/ + /*---- Static factory functions (high level) ----*/ + /** + * Returns a QR Code representing the specified Unicode text string at the specified error correction level. + * As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer + * Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible + * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the + * ecl argument if it can be done without increasing the version. + * @param text the text to be encoded (not {@code null}), which can be any Unicode string + * @param ecl the error correction level to use (not {@code null}) (boostable) + * @return a QR Code (not {@code null}) representing the text + * @throws NullPointerException if the text or error correction level is {@code null} + * @throws IllegalArgumentException if the text fails to fit in the + * largest version QR Code at the ECL, which means it is too long + */ public static QrCode encodeText(String text, Ecc ecl) { Objects.requireNonNull(text); Objects.requireNonNull(ecl); @@ -41,6 +75,18 @@ public final class QrCode { } + /** + * Returns a QR Code representing the specified binary data at the specified error correction level. + * This function always encodes using the binary segment mode, not any text mode. The maximum number of + * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output. + * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version. + * @param data the binary data to encode (not {@code null}) + * @param ecl the error correction level to use (not {@code null}) (boostable) + * @return a QR Code (not {@code null}) representing the data + * @throws NullPointerException if the data or error correction level is {@code null} + * @throws IllegalArgumentException if the data fails to fit in the + * largest version QR Code at the ECL, which means it is too long + */ public static QrCode encodeBinary(byte[] data, Ecc ecl) { Objects.requireNonNull(data); Objects.requireNonNull(ecl); @@ -49,11 +95,51 @@ public final class QrCode { } + /*---- Static factory functions (mid level) ----*/ + + /** + * Returns a QR Code representing the specified segments at the specified error correction + * level. The smallest possible QR Code version is automatically chosen for the output. The ECC level + * of the result may be higher than the ecl argument if it can be done without increasing the version. + *This function allows the user to create a custom sequence of segments that switches + * between modes (such as alphanumeric and byte) to encode text in less space. + * This is a mid-level API; the high-level API is {@link #encodeText(String,Ecc)} + * and {@link #encodeBinary(byte[],Ecc)}.
+ * @param segs the segments to encode + * @param ecl the error correction level to use (not {@code null}) (boostable) + * @return a QR Code (not {@code null}) representing the segments + * @throws NullPointerException if the list of segments, any segment, or the error correction level is {@code null} + * @throws IllegalArgumentException if the segments fail to fit in the + * largest version QR Code at the ECL, which means they are too long + */ public static QrCode encodeSegments(ListThis function allows the user to create a custom sequence of segments that switches + * between modes (such as alphanumeric and byte) to encode text in less space. + * This is a mid-level API; the high-level API is {@link #encodeText(String,Ecc)} + * and {@link #encodeBinary(byte[],Ecc)}.
+ * @param segs the segments to encode + * @param ecl the error correction level to use (not {@code null}) (boostable) + * @param minVersion the minimum allowed version of the QR Code (at least 1) + * @param maxVersion the maximum allowed version of the QR Code (at most 40) + * @param mask the mask number to use (between 0 and 7 (inclusive)), or −1 for automatic mask + * @param boostEcl increases the ECC level as long as it doesn't increase the version number + * @return a QR Code (not {@code null}) representing the segments + * @throws NullPointerException if the list of segments, any segment, or the error correction level is {@code null} + * @throws IllegalArgumentException if 1 ≤ minVersion ≤ maxVersion ≤ 40 + * or −1 ≤ mask ≤ 7 is violated; or if the segments fail to + * fit in the maxVersion QR Code at the ECL, which means they are too long + */ public static QrCode encodeSegments(ListEven if a QR Code is created with automatic masking requested (mask = + * −1), the resulting object still has a mask value between 0 and 7. */ public final int mask; private final int[] modules; - /*---- Constructor ----*/ + /*---- Constructor (low level) ----*/ + /** + * Constructs a QR Code with the specified version number, + * error correction level, data codeword bytes, and mask number. + *
This is a low-level API that most users should not use directly. A mid-level + * API is the {@link #encodeSegments(List,Ecc,int,int,int,boolean)} function.
+ * @param ver the version number to use, which must be in the range 1 to 40 (inclusive) + * @param ecl the error correction level to use + * @param dataCodewords the bytes representing segments to encode (without ECC) + * @param mask the mask pattern to use, which is either −1 for automatic choice or from 0 to 7 for fixed choice + * @throws NullPointerException if the byte array or error correction level is {@code null} + * @throws IllegalArgumentException if the version or mask value is out of range, + * or if the data is the wrong length for the specified version and error correction level + */ public QrCode(int ver, Ecc ecl, byte[] dataCodewords, int mask) { // Check arguments and initialize fields if (ver < MIN_VERSION || ver > MAX_VERSION) @@ -145,12 +252,13 @@ public final class QrCode { /*---- Public instance methods ----*/ /** - * Returns the color of the module (pixel) at the specified coordinates, which is either - * false for white or true for black. The top left corner has the coordinates (x=0, y=0). - * If the specified coordinates are out of bounds, then false (white) is returned. - * @param x the x coordinate, where 0 is the left edge and size−1 is the right edge - * @param y the y coordinate, where 0 is the top edge and size−1 is the bottom edge - * @return the module's color, which is either false (white) or true (black) + * Returns the color of the module (pixel) at the specified coordinates, which is {@code false} + * for white or {@code true} for black. The top left corner has the coordinates (x=0, y=0). + * If the specified coordinates are out of bounds, then {@code false} (white) is returned. + * @param x the x coordinate, where 0 is the left edge and size−1 is the right edge + * @param y the y coordinate, where 0 is the top edge and size−1 is the bottom edge + * @return {@code true} if the coordinates are in bounds and the module + * at that location is black, or {@code false} (white) otherwise */ public boolean getModule(int x, int y) { if (0 <= x && x < size && 0 <= y && y < size) { @@ -162,13 +270,13 @@ public final class QrCode { /** - * Returns a new image object representing this QR Code, with the specified module scale and number - * of border modules. For example, the arguments scale=10, border=4 means to pad the QR Code symbol - * with 4 white border modules on all four edges, then use 10*10 pixels to represent each module. + * Returns a raster image depicting this QR Code, with the specified module scale and border modules. + *For example, toImage(scale=10, border=4) means to pad the QR Code with 4 white + * border modules on all four sides, and use 10×10 pixels to represent each module. * The resulting image only contains the hex colors 000000 and FFFFFF. - * @param scale the module scale factor, which must be positive + * @param scale the side length (measured in pixels, must be positive) of each module * @param border the number of border modules to add, which must be non-negative - * @return an image representing this QR Code, with padding and scaling + * @return a new image representing this QR Code, with padding and scaling * @throws IllegalArgumentException if the scale or border is out of range, or if * {scale, border, size} cause the image dimensions to exceed Integer.MAX_VALUE */ @@ -190,10 +298,10 @@ public final class QrCode { /** - * Returns a string of SVG XML code representing an image of this QR Code symbol with the specified - * number of border modules. Note that Unix newlines (\n) are always used, regardless of the platform. + * Returns a string of SVG code for an image depicting this QR Code, with the specified number + * of border modules. The string always uses Unix newlines (\n), regardless of the platform. * @param border the number of border modules to add, which must be non-negative - * @return a string representing this QR Code as an SVG document + * @return a string representing this QR Code as an SVG XML document * @throws IllegalArgumentException if the border is negative */ public String toSvgString(int border) { @@ -331,7 +439,7 @@ public final class QrCode { } - // A messy helper function for the constructors. This QR Code must be in an unmasked state when this + // A messy helper function for the constructor. This QR Code must be in an unmasked state when this // method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed. // This method applies and returns the actual mask chosen, from 0 to 7. private int handleConstructorMasking(int[][] masks, int mask) { @@ -434,7 +542,7 @@ public final class QrCode { - /*---- Private static helper functions ----*/ + /*---- Private helper functions ----*/ // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any // QR Code of the given version number and error correction level, with remainder bits discarded. @@ -454,7 +562,10 @@ public final class QrCode { /*---- Constants and tables ----*/ + /** The minimum version number (1) supported in the QR Code Model 2 standard. */ public static final int MIN_VERSION = 1; + + /** The maximum version number (40) supported in the QR Code Model 2 standard. */ public static final int MAX_VERSION = 40; @@ -487,10 +598,16 @@ public final class QrCode { /*---- Public helper enumeration ----*/ + /** + * The error correction level in a QR Code symbol. + */ public enum Ecc { - // These enum constants must be declared in ascending order of error protection, - // for the sake of the implicit ordinal() method and values() function. - LOW(1), MEDIUM(0), QUARTILE(3), HIGH(2); + // Must be declared in ascending order of error protection + // so that the implicit ordinal() and values() work properly + /** The QR Code can tolerate about 7% erroneous codewords. */ LOW(1), + /** The QR Code can tolerate about 15% erroneous codewords. */ MEDIUM(0), + /** The QR Code can tolerate about 25% erroneous codewords. */ QUARTILE(3), + /** The QR Code can tolerate about 30% erroneous codewords. */ HIGH(2); // In the range 0 to 3 (unsigned 2-bit integer). final int formatBits; diff --git a/src/io/nayuki/fastqrcodegen/QrSegment.java b/src/io/nayuki/fastqrcodegen/QrSegment.java index ff31a35..ee6a6a2 100644 --- a/src/io/nayuki/fastqrcodegen/QrSegment.java +++ b/src/io/nayuki/fastqrcodegen/QrSegment.java @@ -32,8 +32,17 @@ import java.util.Objects; public final class QrSegment { - /*---- Static factory functions ----*/ - + /*---- Static factory functions (mid level) ----*/ + + /** + * Returns a segment representing the specified binary data + * encoded in byte mode. All input byte arrays are acceptable. + *
Any text string can be converted to UTF-8 bytes ({@code + * s.getBytes(StandardCharsets.UTF_8)}) and encoded as a byte mode segment.
+ * @param data the binary data (not {@code null}) + * @return a segment (not {@code null}) containing the data + * @throws NullPointerException if the array is {@code null} + */ public static QrSegment makeBytes(byte[] data) { Objects.requireNonNull(data); int[] bits = new int[(data.length + 3) / 4]; @@ -43,6 +52,13 @@ public final class QrSegment { } + /** + * Returns a segment representing the specified string of decimal digits encoded in numeric mode. + * @param digits the text (not {@code null}), with only digits from 0 to 9 allowed + * @return a segment (not {@code null}) containing the text + * @throws NullPointerException if the string is {@code null} + * @throws IllegalArgumentException if the string contains non-digit characters + */ public static QrSegment makeNumeric(String digits) { Objects.requireNonNull(digits); BitBuffer bb = new BitBuffer(); @@ -66,6 +82,15 @@ public final class QrSegment { } + /** + * Returns a segment representing the specified text string encoded in alphanumeric mode. + * The characters allowed are: 0 to 9, A to Z (uppercase only), space, + * dollar, percent, asterisk, plus, hyphen, period, slash, colon. + * @param text the text (not {@code null}), with only certain characters allowed + * @return a segment (not {@code null}) containing the text + * @throws NullPointerException if the string is {@code null} + * @throws IllegalArgumentException if the string contains non-encodable characters + */ public static QrSegment makeAlphanumeric(String text) { Objects.requireNonNull(text); BitBuffer bb = new BitBuffer(); @@ -89,6 +114,13 @@ public final class QrSegment { } + /** + * Returns a list of zero or more segments to represent the specified Unicode text string. + * The result may use various segment modes and switch modes to optimize the length of the bit stream. + * @param text the text to be encoded, which can be any Unicode string + * @return a new mutable list (not {@code null}) of segments (not {@code null}) containing the text + * @throws NullPointerException if the text is {@code null} + */ public static List