mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Refactored Reed-Solomon so it can be used with different GF(256) primitive polynomials
git-svn-id: https://zxing.googlecode.com/svn/trunk@209 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
833a8b03f7
commit
cde4d22ece
|
@ -18,8 +18,7 @@ package com.google.zxing.common.reedsolomon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>This class contains utility methods for performing mathematical operations over
|
* <p>This class contains utility methods for performing mathematical operations over
|
||||||
* the Galois Field GF(256). Operations use the primitive polynomial
|
* the Galois Field GF(256). Operations use a given primitive polynomial in calculations.</p>
|
||||||
* x^8 + x^4 + x^3 + x^2 + 1 in calculations.</p>
|
|
||||||
*
|
*
|
||||||
* <p>Throughout this package, elements of GF(256) are represented as an <code>int</code>
|
* <p>Throughout this package, elements of GF(256) are represented as an <code>int</code>
|
||||||
* for convenience and speed (but at the cost of memory).
|
* for convenience and speed (but at the cost of memory).
|
||||||
|
@ -27,28 +26,63 @@ package com.google.zxing.common.reedsolomon;
|
||||||
*
|
*
|
||||||
* @author srowen@google.com (Sean Owen)
|
* @author srowen@google.com (Sean Owen)
|
||||||
*/
|
*/
|
||||||
final class GF256 {
|
public final class GF256 {
|
||||||
|
|
||||||
private static final int PRIMITIVE = 0x011D;
|
public static final GF256 QR_CODE_FIELD = new GF256(0x011D); // x^8 + x^4 + x^3 + x^2 + 1
|
||||||
private static final int[] exp = new int[256];
|
public static final GF256 DATA_MATRIX_FIELD = new GF256(0x012D); // x^8 + x^5 + x^3 + x^2 + 1
|
||||||
private static final int[] log = new int[256];
|
|
||||||
|
|
||||||
static {
|
private final int[] exp;
|
||||||
|
private final int[] log;
|
||||||
|
private final GF256Poly zero;
|
||||||
|
private final GF256Poly one;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a representation of GF(256) 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
|
||||||
|
*/
|
||||||
|
private GF256(int primitive) {
|
||||||
|
exp = new int[256];
|
||||||
|
log = new int[256];
|
||||||
int x = 1;
|
int x = 1;
|
||||||
for (int i = 0; i < 256; i++) {
|
for (int i = 0; i < 256; i++) {
|
||||||
exp[i] = x;
|
exp[i] = x;
|
||||||
x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
|
x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
|
||||||
if (x >= 0x100) {
|
if (x >= 0x100) {
|
||||||
x ^= PRIMITIVE;
|
x ^= primitive;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 255; i++) {
|
for (int i = 0; i < 255; i++) {
|
||||||
log[exp[i]] = i;
|
log[exp[i]] = i;
|
||||||
}
|
}
|
||||||
// log[0] == 0 but this should never be used
|
// log[0] == 0 but this should never be used
|
||||||
|
zero = new GF256Poly(this, new int[]{0});
|
||||||
|
one = new GF256Poly(this, new int[]{1});
|
||||||
}
|
}
|
||||||
|
|
||||||
private GF256() {
|
GF256Poly getZero() {
|
||||||
|
return zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
GF256Poly getOne() {
|
||||||
|
return one;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the monomial representing coefficient * x^degree
|
||||||
|
*/
|
||||||
|
GF256Poly buildMonomial(int degree, int coefficient) {
|
||||||
|
if (degree < 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (coefficient == 0) {
|
||||||
|
return zero;
|
||||||
|
}
|
||||||
|
int[] coefficients = new int[degree + 1];
|
||||||
|
coefficients[0] = coefficient;
|
||||||
|
return new GF256Poly(this, coefficients);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,21 +90,21 @@ final class GF256 {
|
||||||
*
|
*
|
||||||
* @return sum/difference of a and b
|
* @return sum/difference of a and b
|
||||||
*/
|
*/
|
||||||
static int addOrSubtract(int a, int b) {
|
int addOrSubtract(int a, int b) {
|
||||||
return a ^ b;
|
return a ^ b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 2 to the power of a in GF(256)
|
* @return 2 to the power of a in GF(256)
|
||||||
*/
|
*/
|
||||||
static int exp(int a) {
|
int exp(int a) {
|
||||||
return exp[a];
|
return exp[a];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return base 2 log of a in GF(256)
|
* @return base 2 log of a in GF(256)
|
||||||
*/
|
*/
|
||||||
static int log(int a) {
|
int log(int a) {
|
||||||
if (a == 0) {
|
if (a == 0) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
@ -80,7 +114,7 @@ final class GF256 {
|
||||||
/**
|
/**
|
||||||
* @return multiplicative inverse of a
|
* @return multiplicative inverse of a
|
||||||
*/
|
*/
|
||||||
static int inverse(int a) {
|
int inverse(int a) {
|
||||||
if (a == 0) {
|
if (a == 0) {
|
||||||
throw new ArithmeticException();
|
throw new ArithmeticException();
|
||||||
}
|
}
|
||||||
|
@ -92,7 +126,7 @@ final class GF256 {
|
||||||
* @param b
|
* @param b
|
||||||
* @return product of a and b in GF(256)
|
* @return product of a and b in GF(256)
|
||||||
*/
|
*/
|
||||||
static int multiply(int a, int b) {
|
int multiply(int a, int b) {
|
||||||
if (a == 0 || b == 0) {
|
if (a == 0 || b == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,28 +27,23 @@ package com.google.zxing.common.reedsolomon;
|
||||||
*/
|
*/
|
||||||
final class GF256Poly {
|
final class GF256Poly {
|
||||||
|
|
||||||
/**
|
private final GF256 field;
|
||||||
* Polynimal representing the monomial 0.
|
|
||||||
*/
|
|
||||||
static final GF256Poly ZERO = new GF256Poly(new int[]{0});
|
|
||||||
/**
|
|
||||||
* Polynimal representing the monomial 1.
|
|
||||||
*/
|
|
||||||
static final GF256Poly ONE = new GF256Poly(new int[]{1});
|
|
||||||
|
|
||||||
private final int[] coefficients;
|
private final int[] coefficients;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param field the {@link GF256} instance representing the field to use
|
||||||
|
* to perform computations
|
||||||
* @param coefficients coefficients as ints representing elements of GF(256), arranged
|
* @param coefficients coefficients as ints representing elements of GF(256), arranged
|
||||||
* from most significant (highest-power term) coefficient to least significant
|
* from most significant (highest-power term) coefficient to least significant
|
||||||
* @throws IllegalArgumentException if argument is null or empty,
|
* @throws IllegalArgumentException if argument is null or empty,
|
||||||
* or if leading coefficient is 0 and this is not a
|
* or if leading coefficient is 0 and this is not a
|
||||||
* constant polynomial (that is, it is not the monomial "0")
|
* constant polynomial (that is, it is not the monomial "0")
|
||||||
*/
|
*/
|
||||||
GF256Poly(int[] coefficients) {
|
GF256Poly(GF256 field, int[] coefficients) {
|
||||||
if (coefficients == null || coefficients.length == 0) {
|
if (coefficients == null || coefficients.length == 0) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
this.field = field;
|
||||||
if (coefficients.length > 1 && coefficients[0] == 0) {
|
if (coefficients.length > 1 && coefficients[0] == 0) {
|
||||||
// Leading term must be non-zero for anything except the constant polynomial "0"
|
// Leading term must be non-zero for anything except the constant polynomial "0"
|
||||||
int firstNonZero = 1;
|
int firstNonZero = 1;
|
||||||
|
@ -56,7 +51,7 @@ final class GF256Poly {
|
||||||
firstNonZero++;
|
firstNonZero++;
|
||||||
}
|
}
|
||||||
if (firstNonZero == coefficients.length) {
|
if (firstNonZero == coefficients.length) {
|
||||||
this.coefficients = ZERO.coefficients;
|
this.coefficients = field.getZero().coefficients;
|
||||||
} else {
|
} else {
|
||||||
this.coefficients = new int[coefficients.length - firstNonZero];
|
this.coefficients = new int[coefficients.length - firstNonZero];
|
||||||
System.arraycopy(coefficients,
|
System.arraycopy(coefficients,
|
||||||
|
@ -84,21 +79,6 @@ final class GF256Poly {
|
||||||
return coefficients[0] == 0;
|
return coefficients[0] == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the monomial representing coefficient * x^degree
|
|
||||||
*/
|
|
||||||
static GF256Poly buildMonomial(int degree, int coefficient) {
|
|
||||||
if (degree < 0) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
if (coefficient == 0) {
|
|
||||||
return ZERO;
|
|
||||||
}
|
|
||||||
int[] coefficients = new int[degree + 1];
|
|
||||||
coefficients[0] = coefficient;
|
|
||||||
return new GF256Poly(coefficients);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return coefficient of x^degree term in this polynomial
|
* @return coefficient of x^degree term in this polynomial
|
||||||
*/
|
*/
|
||||||
|
@ -114,18 +94,18 @@ final class GF256Poly {
|
||||||
// Just return the x^0 coefficient
|
// Just return the x^0 coefficient
|
||||||
return getCoefficient(0);
|
return getCoefficient(0);
|
||||||
}
|
}
|
||||||
final int size = coefficients.length;
|
int size = coefficients.length;
|
||||||
if (a == 1) {
|
if (a == 1) {
|
||||||
// Just the sum of the coefficients
|
// Just the sum of the coefficients
|
||||||
int result = 0;
|
int result = 0;
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
result = GF256.addOrSubtract(result, coefficients[i]);
|
result = field.addOrSubtract(result, coefficients[i]);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
int result = coefficients[0];
|
int result = coefficients[0];
|
||||||
for (int i = 1; i < size; i++) {
|
for (int i = 1; i < size; i++) {
|
||||||
result = GF256.addOrSubtract(GF256.multiply(a, result), coefficients[i]);
|
result = field.addOrSubtract(field.multiply(a, result), coefficients[i]);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -139,15 +119,18 @@ final class GF256Poly {
|
||||||
|
|
||||||
int aToTheI = 1;
|
int aToTheI = 1;
|
||||||
int sum = getCoefficient(1);
|
int sum = getCoefficient(1);
|
||||||
int aSquared = GF256.multiply(a, a);
|
int aSquared = field.multiply(a, a);
|
||||||
for (int i = 2; i < degree; i += 2) {
|
for (int i = 2; i < degree; i += 2) {
|
||||||
aToTheI = GF256.multiply(aSquared, aToTheI);
|
aToTheI = field.multiply(aSquared, aToTheI);
|
||||||
sum = GF256.addOrSubtract(sum, GF256.multiply(aToTheI, getCoefficient(i + 1)));
|
sum = field.addOrSubtract(sum, field.multiply(aToTheI, getCoefficient(i + 1)));
|
||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
GF256Poly addOrSubtract(GF256Poly other) {
|
GF256Poly addOrSubtract(GF256Poly other) {
|
||||||
|
if (!field.equals(other.field)) {
|
||||||
|
throw new IllegalArgumentException("GF256Polys do not have same GF256 field");
|
||||||
|
}
|
||||||
if (isZero()) {
|
if (isZero()) {
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
|
@ -168,15 +151,18 @@ final class GF256Poly {
|
||||||
System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
|
System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
|
||||||
|
|
||||||
for (int i = lengthDiff; i < largerCoefficients.length; i++) {
|
for (int i = lengthDiff; i < largerCoefficients.length; i++) {
|
||||||
sumDiff[i] = GF256.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
|
sumDiff[i] = field.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GF256Poly(sumDiff);
|
return new GF256Poly(field, sumDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
GF256Poly multiply(GF256Poly other) {
|
GF256Poly multiply(GF256Poly other) {
|
||||||
|
if (!field.equals(other.field)) {
|
||||||
|
throw new IllegalArgumentException("GF256Polys do not have same GF256 field");
|
||||||
|
}
|
||||||
if (isZero() || other.isZero()) {
|
if (isZero() || other.isZero()) {
|
||||||
return ZERO;
|
return field.getZero();
|
||||||
}
|
}
|
||||||
int[] aCoefficients = this.coefficients;
|
int[] aCoefficients = this.coefficients;
|
||||||
int aLength = aCoefficients.length;
|
int aLength = aCoefficients.length;
|
||||||
|
@ -186,16 +172,16 @@ final class GF256Poly {
|
||||||
for (int i = 0; i < aLength; i++) {
|
for (int i = 0; i < aLength; i++) {
|
||||||
int aCoeff = aCoefficients[i];
|
int aCoeff = aCoefficients[i];
|
||||||
for (int j = 0; j < bLength; j++) {
|
for (int j = 0; j < bLength; j++) {
|
||||||
product[i + j] = GF256.addOrSubtract(product[i + j],
|
product[i + j] = field.addOrSubtract(product[i + j],
|
||||||
GF256.multiply(aCoeff, bCoefficients[j]));
|
field.multiply(aCoeff, bCoefficients[j]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new GF256Poly(product);
|
return new GF256Poly(field, product);
|
||||||
}
|
}
|
||||||
|
|
||||||
GF256Poly multiply(int scalar) {
|
GF256Poly multiply(int scalar) {
|
||||||
if (scalar == 0) {
|
if (scalar == 0) {
|
||||||
return ZERO;
|
return field.getZero();
|
||||||
}
|
}
|
||||||
if (scalar == 1) {
|
if (scalar == 1) {
|
||||||
return this;
|
return this;
|
||||||
|
@ -204,9 +190,9 @@ final class GF256Poly {
|
||||||
int[] product = new int[size];
|
int[] product = new int[size];
|
||||||
System.arraycopy(coefficients, 0, product, 0, size);
|
System.arraycopy(coefficients, 0, product, 0, size);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
product[i] = GF256.multiply(product[i], scalar);
|
product[i] = field.multiply(product[i], scalar);
|
||||||
}
|
}
|
||||||
return new GF256Poly(product);
|
return new GF256Poly(field, product);
|
||||||
}
|
}
|
||||||
|
|
||||||
GF256Poly multiplyByMonomial(int degree, int coefficient) {
|
GF256Poly multiplyByMonomial(int degree, int coefficient) {
|
||||||
|
@ -214,15 +200,15 @@ final class GF256Poly {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
if (coefficient == 0) {
|
if (coefficient == 0) {
|
||||||
return ZERO;
|
return field.getZero();
|
||||||
}
|
}
|
||||||
int size = coefficients.length;
|
int size = coefficients.length;
|
||||||
int[] product = new int[size + degree];
|
int[] product = new int[size + degree];
|
||||||
System.arraycopy(coefficients, 0, product, 0, size);
|
System.arraycopy(coefficients, 0, product, 0, size);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
product[i] = GF256.multiply(product[i], coefficient);
|
product[i] = field.multiply(product[i], coefficient);
|
||||||
}
|
}
|
||||||
return new GF256Poly(product);
|
return new GF256Poly(field, product);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,10 @@ import java.util.Vector;
|
||||||
*/
|
*/
|
||||||
public final class ReedSolomonDecoder {
|
public final class ReedSolomonDecoder {
|
||||||
|
|
||||||
private ReedSolomonDecoder() {
|
private final GF256 field;
|
||||||
|
|
||||||
|
public ReedSolomonDecoder(GF256 field) {
|
||||||
|
this.field = field;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,26 +56,26 @@ public final class ReedSolomonDecoder {
|
||||||
* @param twoS number of error-correction codewords available
|
* @param twoS number of error-correction codewords available
|
||||||
* @throws ReedSolomonException if decoding fails for any reaosn
|
* @throws ReedSolomonException if decoding fails for any reaosn
|
||||||
*/
|
*/
|
||||||
public static void decode(int[] received, int twoS) throws ReedSolomonException {
|
public void decode(int[] received, int twoS) throws ReedSolomonException {
|
||||||
GF256Poly poly = new GF256Poly(received);
|
GF256Poly poly = new GF256Poly(field, received);
|
||||||
int[] syndromeCoefficients = new int[twoS];
|
int[] syndromeCoefficients = new int[twoS];
|
||||||
for (int i = 0; i < twoS; i++) {
|
for (int i = 0; i < twoS; i++) {
|
||||||
syndromeCoefficients[syndromeCoefficients.length - 1 - i] = poly.evaluateAt(GF256.exp(i));
|
syndromeCoefficients[syndromeCoefficients.length - 1 - i] = poly.evaluateAt(field.exp(i));
|
||||||
}
|
}
|
||||||
GF256Poly syndrome = new GF256Poly(syndromeCoefficients);
|
GF256Poly syndrome = new GF256Poly(field, syndromeCoefficients);
|
||||||
if (!syndrome.isZero()) { // Error
|
if (!syndrome.isZero()) { // Error
|
||||||
GF256Poly[] sigmaOmega =
|
GF256Poly[] sigmaOmega =
|
||||||
runEuclideanAlgorithm(GF256Poly.buildMonomial(twoS, 1), syndrome, twoS);
|
runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
|
||||||
int[] errorLocations = findErrorLocations(sigmaOmega[0]);
|
int[] errorLocations = findErrorLocations(sigmaOmega[0]);
|
||||||
int[] errorMagnitudes = findErrorMagnitudes(sigmaOmega[1], errorLocations);
|
int[] errorMagnitudes = findErrorMagnitudes(sigmaOmega[1], errorLocations);
|
||||||
for (int i = 0; i < errorLocations.length; i++) {
|
for (int i = 0; i < errorLocations.length; i++) {
|
||||||
int position = received.length - 1 - GF256.log(errorLocations[i]);
|
int position = received.length - 1 - field.log(errorLocations[i]);
|
||||||
received[position] = GF256.addOrSubtract(received[position], errorMagnitudes[i]);
|
received[position] = field.addOrSubtract(received[position], errorMagnitudes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GF256Poly[] runEuclideanAlgorithm(GF256Poly a, GF256Poly b, int R)
|
private GF256Poly[] runEuclideanAlgorithm(GF256Poly a, GF256Poly b, int R)
|
||||||
throws ReedSolomonException {
|
throws ReedSolomonException {
|
||||||
// Assume a's degree is >= b's
|
// Assume a's degree is >= b's
|
||||||
if (a.getDegree() < b.getDegree()) {
|
if (a.getDegree() < b.getDegree()) {
|
||||||
|
@ -83,10 +86,10 @@ public final class ReedSolomonDecoder {
|
||||||
|
|
||||||
GF256Poly rLast = a;
|
GF256Poly rLast = a;
|
||||||
GF256Poly r = b;
|
GF256Poly r = b;
|
||||||
GF256Poly sLast = GF256Poly.ONE;
|
GF256Poly sLast = field.getOne();
|
||||||
GF256Poly s = GF256Poly.ZERO;
|
GF256Poly s = field.getZero();
|
||||||
GF256Poly tLast = GF256Poly.ZERO;
|
GF256Poly tLast = field.getZero();
|
||||||
GF256Poly t = GF256Poly.ONE;
|
GF256Poly t = field.getOne();
|
||||||
|
|
||||||
// Run Euclidean algorithm until r's degree is less than R/2
|
// Run Euclidean algorithm until r's degree is less than R/2
|
||||||
while (r.getDegree() >= R / 2) {
|
while (r.getDegree() >= R / 2) {
|
||||||
|
@ -103,13 +106,13 @@ public final class ReedSolomonDecoder {
|
||||||
throw new ReedSolomonException("r_{i-1} was zero");
|
throw new ReedSolomonException("r_{i-1} was zero");
|
||||||
}
|
}
|
||||||
r = rLastLast;
|
r = rLastLast;
|
||||||
GF256Poly q = GF256Poly.ZERO;
|
GF256Poly q = field.getZero();
|
||||||
int denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree());
|
int denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree());
|
||||||
int dltInverse = GF256.inverse(denominatorLeadingTerm);
|
int dltInverse = field.inverse(denominatorLeadingTerm);
|
||||||
while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
|
while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
|
||||||
int degreeDiff = r.getDegree() - rLast.getDegree();
|
int degreeDiff = r.getDegree() - rLast.getDegree();
|
||||||
int scale = GF256.multiply(r.getCoefficient(r.getDegree()), dltInverse);
|
int scale = field.multiply(r.getCoefficient(r.getDegree()), dltInverse);
|
||||||
q = q.addOrSubtract(GF256Poly.buildMonomial(degreeDiff, scale));
|
q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale));
|
||||||
r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
|
r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,19 +125,19 @@ public final class ReedSolomonDecoder {
|
||||||
throw new ReedSolomonException("sigmaTilde(0) was zero");
|
throw new ReedSolomonException("sigmaTilde(0) was zero");
|
||||||
}
|
}
|
||||||
|
|
||||||
int inverse = GF256.inverse(sigmaTildeAtZero);
|
int inverse = field.inverse(sigmaTildeAtZero);
|
||||||
GF256Poly sigma = t.multiply(inverse);
|
GF256Poly sigma = t.multiply(inverse);
|
||||||
GF256Poly omega = r.multiply(inverse);
|
GF256Poly omega = r.multiply(inverse);
|
||||||
return new GF256Poly[]{sigma, omega};
|
return new GF256Poly[]{sigma, omega};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int[] findErrorLocations(GF256Poly errorLocator)
|
private int[] findErrorLocations(GF256Poly errorLocator)
|
||||||
throws ReedSolomonException {
|
throws ReedSolomonException {
|
||||||
// This is a direct application of Chien's search
|
// This is a direct application of Chien's search
|
||||||
Vector errorLocations = new Vector(3);
|
Vector errorLocations = new Vector(3);
|
||||||
for (int i = 1; i < 256; i++) {
|
for (int i = 1; i < 256; i++) {
|
||||||
if (errorLocator.evaluateAt(i) == 0) {
|
if (errorLocator.evaluateAt(i) == 0) {
|
||||||
errorLocations.addElement(new Integer(GF256.inverse(i)));
|
errorLocations.addElement(new Integer(field.inverse(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (errorLocations.size() != errorLocator.getDegree()) {
|
if (errorLocations.size() != errorLocator.getDegree()) {
|
||||||
|
@ -147,22 +150,22 @@ public final class ReedSolomonDecoder {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int[] findErrorMagnitudes(GF256Poly errorEvaluator,
|
private int[] findErrorMagnitudes(GF256Poly errorEvaluator,
|
||||||
int[] errorLocations) {
|
int[] errorLocations) {
|
||||||
// This is directly applying Forney's Formula
|
// This is directly applying Forney's Formula
|
||||||
int s = errorLocations.length;
|
int s = errorLocations.length;
|
||||||
int[] result = new int[s];
|
int[] result = new int[s];
|
||||||
for (int i = 0; i < errorLocations.length; i++) {
|
for (int i = 0; i < errorLocations.length; i++) {
|
||||||
int xiInverse = GF256.inverse(errorLocations[i]);
|
int xiInverse = field.inverse(errorLocations[i]);
|
||||||
int denominator = 1;
|
int denominator = 1;
|
||||||
for (int j = 0; j < s; j++) {
|
for (int j = 0; j < s; j++) {
|
||||||
if (i != j) {
|
if (i != j) {
|
||||||
denominator = GF256.multiply(denominator,
|
denominator = field.multiply(denominator,
|
||||||
GF256.addOrSubtract(1, GF256.multiply(errorLocations[j], xiInverse)));
|
field.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result[i] = GF256.multiply(errorEvaluator.evaluateAt(xiInverse),
|
result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse),
|
||||||
GF256.inverse(denominator));
|
field.inverse(denominator));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ public final class QRCodeReader implements Reader {
|
||||||
|
|
||||||
private static final ResultPoint[] NO_POINTS = new ResultPoint[0];
|
private static final ResultPoint[] NO_POINTS = new ResultPoint[0];
|
||||||
|
|
||||||
|
private final Decoder decoder = new Decoder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locates and decodes a QR code in an image.
|
* Locates and decodes a QR code in an image.
|
||||||
*
|
*
|
||||||
|
@ -54,11 +56,11 @@ public final class QRCodeReader implements Reader {
|
||||||
ResultPoint[] points;
|
ResultPoint[] points;
|
||||||
if (hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE)) {
|
if (hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE)) {
|
||||||
BitMatrix bits = extractPureBits(image);
|
BitMatrix bits = extractPureBits(image);
|
||||||
text = Decoder.decode(bits);
|
text = decoder.decode(bits);
|
||||||
points = NO_POINTS;
|
points = NO_POINTS;
|
||||||
} else {
|
} else {
|
||||||
DetectorResult result = new Detector(image).detect();
|
DetectorResult result = new Detector(image).detect();
|
||||||
text = Decoder.decode(result.getBits());
|
text = decoder.decode(result.getBits());
|
||||||
points = result.getPoints();
|
points = result.getPoints();
|
||||||
}
|
}
|
||||||
return new Result(text, points);
|
return new Result(text, points);
|
||||||
|
|
|
@ -18,6 +18,7 @@ package com.google.zxing.qrcode.decoder;
|
||||||
|
|
||||||
import com.google.zxing.ReaderException;
|
import com.google.zxing.ReaderException;
|
||||||
import com.google.zxing.common.BitMatrix;
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
import com.google.zxing.common.reedsolomon.GF256;
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
||||||
|
|
||||||
|
@ -29,7 +30,10 @@ import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
||||||
*/
|
*/
|
||||||
public final class Decoder {
|
public final class Decoder {
|
||||||
|
|
||||||
private Decoder() {
|
private final ReedSolomonDecoder rsDecoder;
|
||||||
|
|
||||||
|
public Decoder() {
|
||||||
|
rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,7 +44,7 @@ public final class Decoder {
|
||||||
* @return text encoded within the QR Code
|
* @return text encoded within the QR Code
|
||||||
* @throws ReaderException if the QR Code cannot be decoded
|
* @throws ReaderException if the QR Code cannot be decoded
|
||||||
*/
|
*/
|
||||||
public static String decode(boolean[][] image) throws ReaderException {
|
public String decode(boolean[][] image) throws ReaderException {
|
||||||
int dimension = image.length;
|
int dimension = image.length;
|
||||||
BitMatrix bits = new BitMatrix(dimension);
|
BitMatrix bits = new BitMatrix(dimension);
|
||||||
for (int i = 0; i < dimension; i++) {
|
for (int i = 0; i < dimension; i++) {
|
||||||
|
@ -60,7 +64,7 @@ public final class Decoder {
|
||||||
* @return text encoded within the QR Code
|
* @return text encoded within the QR Code
|
||||||
* @throws ReaderException if the QR Code cannot be decoded
|
* @throws ReaderException if the QR Code cannot be decoded
|
||||||
*/
|
*/
|
||||||
public static String decode(BitMatrix bits) throws ReaderException {
|
public String decode(BitMatrix bits) throws ReaderException {
|
||||||
|
|
||||||
// Construct a parser and read version, error-correction level
|
// Construct a parser and read version, error-correction level
|
||||||
BitMatrixParser parser = new BitMatrixParser(bits);
|
BitMatrixParser parser = new BitMatrixParser(bits);
|
||||||
|
@ -103,7 +107,7 @@ public final class Decoder {
|
||||||
* @param numDataCodewords number of codewords that are data bytes
|
* @param numDataCodewords number of codewords that are data bytes
|
||||||
* @throws ReaderException if error correction fails
|
* @throws ReaderException if error correction fails
|
||||||
*/
|
*/
|
||||||
private static void correctErrors(byte[] codewordBytes, int numDataCodewords) throws ReaderException {
|
private void correctErrors(byte[] codewordBytes, int numDataCodewords) throws ReaderException {
|
||||||
int numCodewords = codewordBytes.length;
|
int numCodewords = codewordBytes.length;
|
||||||
// First read into an array of ints
|
// First read into an array of ints
|
||||||
int[] codewordsInts = new int[numCodewords];
|
int[] codewordsInts = new int[numCodewords];
|
||||||
|
@ -112,7 +116,7 @@ public final class Decoder {
|
||||||
}
|
}
|
||||||
int numECCodewords = codewordBytes.length - numDataCodewords;
|
int numECCodewords = codewordBytes.length - numDataCodewords;
|
||||||
try {
|
try {
|
||||||
ReedSolomonDecoder.decode(codewordsInts, numECCodewords);
|
rsDecoder.decode(codewordsInts, numECCodewords);
|
||||||
} catch (ReedSolomonException rse) {
|
} catch (ReedSolomonException rse) {
|
||||||
throw new ReaderException(rse.toString());
|
throw new ReaderException(rse.toString());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue