diff --git a/src/io/nayuki/fastqrcodegen/BitBuffer.java b/src/io/nayuki/fastqrcodegen/BitBuffer.java index 18e1027..fafafd5 100644 --- a/src/io/nayuki/fastqrcodegen/BitBuffer.java +++ b/src/io/nayuki/fastqrcodegen/BitBuffer.java @@ -27,24 +27,20 @@ import java.util.Arrays; import java.util.Objects; -/** - * An appendable sequence of bits (0s and 1s). Mainly used by {@link QrSegment}. - */ +// An appendable sequence of bits (0s and 1s), mainly used by QrSegment. final class BitBuffer { /*---- Fields ----*/ - int[] data; + int[] data; // In each 32-bit word, bits are filled from top down. - int bitLength; + int bitLength; // Always non-negative. /*---- Constructor ----*/ - /** - * Constructs an empty bit buffer (length 0). - */ + // Creates an empty bit buffer. public BitBuffer() { data = new int[64]; bitLength = 0; @@ -54,10 +50,7 @@ final class BitBuffer { /*---- Methods ----*/ - /** - * Returns the length of this sequence, which is a non-negative value. - * @return the length of this sequence - */ + // Returns the bit at the given index, yielding 0 or 1. public int getBit(int index) { if (index < 0 || index >= bitLength) throw new IndexOutOfBoundsException(); @@ -65,11 +58,8 @@ final class BitBuffer { } - /** - * Returns an array representing this buffer's bits packed into bytes - * in big endian. The current bit length must be a multiple of 8. - * @return a new byte array (not {@code null}) representing this bit sequence - */ + // Returns a new array representing this buffer's bits packed into + // bytes in big endian. The current bit length must be a multiple of 8. public byte[] getBytes() { if (bitLength % 8 != 0) throw new IllegalStateException("Data is not a whole number of bytes"); @@ -80,15 +70,8 @@ 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 - */ + // Appends the given number of low-order bits of the given value + // to this buffer. Requires 0 <= len <= 31 and 0 <= val < 2^len. public void appendBits(int val, int len) { if (len < 0 || len > 31 || val >>> len != 0) throw new IllegalArgumentException("Value out of range"); @@ -114,14 +97,8 @@ final class BitBuffer { } - /** - * Appends the specified sequence of bits to this buffer. - * Requires 0 ≤ len ≤ 32 × vals.length. - * @param vals the sequence of bits to append (not {@code null}) - * @param len the number of prefix bits to read from the array - * @throws IllegalStateException if appending the data - * would make bitLength exceed Integer.MAX_VALUE - */ + // Appends to this buffer the sequence of bits represented by the given + // word array and given bit length. Requires 0 <= len <= 32 * vals.length. public void appendBits(int[] vals, int len) { Objects.requireNonNull(vals); if (len == 0) diff --git a/src/io/nayuki/fastqrcodegen/QrCode.java b/src/io/nayuki/fastqrcodegen/QrCode.java index e25f377..31c9a6e 100644 --- a/src/io/nayuki/fastqrcodegen/QrCode.java +++ b/src/io/nayuki/fastqrcodegen/QrCode.java @@ -215,9 +215,8 @@ public final class QrCode { * −1), the resulting object still has a mask value between 0 and 7. */ public final int mask; - // Private grid of modules/pixels: - - // The modules of this QR Code. Immutable after constructor finishes. Accessed through getModule(). + // Private grid of modules of this QR Code, packed tightly into bits. + // Immutable after constructor finishes. Accessed through getModule(). private final int[] modules; @@ -424,8 +423,8 @@ public final class QrCode { } - // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire - // data area of this QR Code symbol. Function modules need to be marked off before this is called. + // Draws the given sequence of 8-bit codewords (data and error correction) + // onto the entire data area of this QR Code, based on the given bit indexes. private void drawCodewords(int[] dataOutputBitIndexes, byte[] allCodewords) { Objects.requireNonNull(dataOutputBitIndexes); Objects.requireNonNull(allCodewords); @@ -443,7 +442,7 @@ public final class QrCode { // The function modules must be marked and the codeword bits must be drawn // before masking. Due to the arithmetic of XOR, calling applyMask() with // the same mask value a second time will undo the mask. A final well-formed - // QR Code symbol needs exactly one (not zero, two, etc.) mask applied. + // QR Code needs exactly one (not zero, two, etc.) mask applied. private void applyMask(int[] mask) { if (mask.length != modules.length) throw new IllegalArgumentException(); @@ -453,7 +452,7 @@ public final class QrCode { // 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. + // method is called. The 'mask' 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) { if (mask == -1) { // Automatically choose best mask diff --git a/src/io/nayuki/fastqrcodegen/QrTemplate.java b/src/io/nayuki/fastqrcodegen/QrTemplate.java index 98cdeb7..b774cce 100644 --- a/src/io/nayuki/fastqrcodegen/QrTemplate.java +++ b/src/io/nayuki/fastqrcodegen/QrTemplate.java @@ -24,23 +24,28 @@ package io.nayuki.fastqrcodegen; +// Stores the parts of a QR Code that depend only on the version number, +// and does not depend on the data or error correction level or mask. final class QrTemplate { + // Use this memoizer to get instances of this class. public static final Memoizer MEMOIZER = new Memoizer<>(QrTemplate::new); - private final int version; - private final int size; + private final int version; // In the range [1, 40]. + private final int size; // Derived from version. - final int[] template; - final int[][] masks; - final int[] dataOutputBitIndexes; + final int[] template; // Length and values depend on version. + final int[][] masks; // masks.length == 8, and masks[i].length == template.length. + final int[] dataOutputBitIndexes; // Length and values depend on version. // Indicates function modules that are not subjected to masking. Discarded when constructor finishes. + // Otherwise when the constructor is running, isFunction.length == template.length. private int[] isFunction; + // Creates a QR Code template for the given version number. private QrTemplate(int ver) { if (ver < QrCode.MIN_VERSION || ver > QrCode.MAX_VERSION) throw new IllegalArgumentException("Version out of range"); @@ -56,6 +61,7 @@ final class QrTemplate { } + // Reads this object's version field, and draws and marks all function modules. private void drawFunctionPatterns() { // Draw horizontal and vertical timing patterns for (int i = 0; i < size; i++) { @@ -101,7 +107,7 @@ final class QrTemplate { darkenFunctionModule(size - 1 - i, 8, 0); for (int i = 8; i < 15; i++) darkenFunctionModule(8, size - 15 + i, 0); - darkenFunctionModule(8, size - 8, 1); + darkenFunctionModule(8, size - 8, 1); // Always black } @@ -153,6 +159,7 @@ final class QrTemplate { } + // Computes and returns a new array of masks, based on this object's various fields. private int[][] generateMasks() { int[][] result = new int[8][template.length]; for (int mask = 0; mask < result.length; mask++) { @@ -180,6 +187,7 @@ final class QrTemplate { } + // Computes and returns an array of bit indexes, based on this object's various fields. private int[] generateZigzagScan() { int[] result = new int[getNumRawDataModules(version) / 8 * 8]; int i = 0; // Bit index into the data @@ -203,6 +211,7 @@ final class QrTemplate { } + // Returns the value of the bit at the given coordinates in the given grid. private int getModule(int[] grid, int x, int y) { assert 0 <= x && x < size; assert 0 <= y && y < size; diff --git a/src/io/nayuki/fastqrcodegen/ReedSolomonGenerator.java b/src/io/nayuki/fastqrcodegen/ReedSolomonGenerator.java index 971aa02..cb2def7 100644 --- a/src/io/nayuki/fastqrcodegen/ReedSolomonGenerator.java +++ b/src/io/nayuki/fastqrcodegen/ReedSolomonGenerator.java @@ -27,29 +27,31 @@ import java.util.Arrays; import java.util.Objects; +// Computes Reed-Solomon error correction codewords for given data codewords. final class ReedSolomonGenerator { + // Use this memoizer to get instances of this class. public static final Memoizer MEMOIZER = new Memoizer<>(ReedSolomonGenerator::new); // A table of size 256 * degree, where polynomialMultiply[i][j] = multiply(i, coefficients[j]). - // 'coefficients' is the temporary array representing the coefficients of the divisor polynomial, - // stored from highest to lowest power, excluding the leading term which is always 1. - // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}. + // 'coefficients' is the temporary array computed in the constructor. private byte[][] polynomialMultiply; + // Creates a Reed-Solomon ECC generator polynomial for the given degree. private ReedSolomonGenerator(int degree) { if (degree < 1 || degree > 255) throw new IllegalArgumentException("Degree out of range"); - // Start with the monomial x^0 + // The divisor polynomial, whose coefficients are stored from highest to lowest power. + // For example, x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}. byte[] coefficients = new byte[degree]; - coefficients[degree - 1] = 1; + coefficients[degree - 1] = 1; // Start off with the monomial x^0 // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), - // drop the highest term, and store the rest of the coefficients in order of descending powers. + // and drop the highest monomial term which is always 1x^degree. // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). int root = 1; for (int i = 0; i < degree; i++) { @@ -70,15 +72,15 @@ final class ReedSolomonGenerator { } + // Returns the error correction codeword for the given data polynomial and this divisor polynomial. public void getRemainder(byte[] data, int dataOff, int dataLen, byte[] result) { Objects.requireNonNull(data); Objects.requireNonNull(result); int degree = polynomialMultiply[0].length; assert result.length == degree; - // Compute the remainder by performing polynomial division Arrays.fill(result, (byte)0); - for (int i = dataOff, dataEnd = dataOff + dataLen; i < dataEnd; i++) { + for (int i = dataOff, dataEnd = dataOff + dataLen; i < dataEnd; i++) { // Polynomial division byte[] table = polynomialMultiply[(data[i] ^ result[0]) & 0xFF]; for (int j = 0; j < degree - 1; j++) result[j] = (byte)(result[j + 1] ^ table[j]);