Added and updated many comments, almost all at the member level (rarely within functions), some with original wording, some synchronizing with the main qrcodegen project.

pull/134/head
Project Nayuki 5 years ago
parent 960b9cd32d
commit 6d6e0f3fde

@ -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 &#x2264; len &#x2264; 31 and 0 &#x2264; val &lt; 2<sup>len</sup>.
* @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 &#x2264; len &#x2264; 32 &#xD7; 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)

@ -215,9 +215,8 @@ public final class QrCode {
* &#x2212;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

@ -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<Integer,QrTemplate> 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;

@ -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<Integer,ReedSolomonGenerator> 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]);

Loading…
Cancel
Save