mirror of
https://github.com/zxing/zxing.git
synced 2024-11-10 04:54:04 -08:00
Added Reed-Solomon encoder, suitable for QR Code encoding
git-svn-id: https://zxing.googlecode.com/svn/trunk@699 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
5dba28fc86
commit
7cae0d4cc9
|
@ -66,6 +66,10 @@ final class GF256Poly {
|
|||
}
|
||||
}
|
||||
|
||||
int[] getCoefficients() {
|
||||
return coefficients;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return degree of this polynomial
|
||||
*/
|
||||
|
@ -111,25 +115,6 @@ final class GF256Poly {
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
int evaluateFormatDerivativeAt(int a) {
|
||||
int degree = getDegree();
|
||||
if (degree == 0) {
|
||||
// Derivative of a constant is zero.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aToTheI = 1;
|
||||
int sum = getCoefficient(1);
|
||||
int aSquared = field.multiply(a, a);
|
||||
for (int i = 2; i < degree; i += 2) {
|
||||
aToTheI = field.multiply(aSquared, aToTheI);
|
||||
sum = field.addOrSubtract(sum, field.multiply(aToTheI, getCoefficient(i + 1)));
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
*/
|
||||
|
||||
GF256Poly addOrSubtract(GF256Poly other) {
|
||||
if (!field.equals(other.field)) {
|
||||
throw new IllegalArgumentException("GF256Polys do not have same GF256 field");
|
||||
|
@ -212,4 +197,67 @@ final class GF256Poly {
|
|||
return new GF256Poly(field, product);
|
||||
}
|
||||
|
||||
GF256Poly[] divide(GF256Poly other) {
|
||||
if (!field.equals(other.field)) {
|
||||
throw new IllegalArgumentException("GF256Polys do not have same GF256 field");
|
||||
}
|
||||
if (other.isZero()) {
|
||||
throw new IllegalArgumentException("Divide by 0");
|
||||
}
|
||||
|
||||
GF256Poly quotient = field.getZero();
|
||||
GF256Poly 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);
|
||||
GF256Poly term = other.multiplyByMonomial(degreeDifference, scale);
|
||||
GF256Poly iterationQuotient = field.buildMonomial(degreeDifference, scale);
|
||||
quotient = quotient.addOrSubtract(iterationQuotient);
|
||||
remainder = remainder.addOrSubtract(term);
|
||||
}
|
||||
|
||||
return new GF256Poly[] { quotient, remainder };
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer result = new StringBuffer(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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.Vector;
|
||||
|
||||
/**
|
||||
* <p>Implements Reed-Solomon enbcoding, as the name implies.</p>
|
||||
*
|
||||
* @author srowen@google.com (Sean Owen)
|
||||
* @author William Rucklidge
|
||||
*/
|
||||
public final class ReedSolomonEncoder {
|
||||
|
||||
private final GF256 field;
|
||||
private final Vector cachedGenerators;
|
||||
|
||||
public ReedSolomonEncoder(GF256 field) {
|
||||
if (!GF256.QR_CODE_FIELD.equals(field)) {
|
||||
throw new IllegalArgumentException("Only QR Code is supported at this time");
|
||||
}
|
||||
this.field = field;
|
||||
this.cachedGenerators = new Vector();
|
||||
cachedGenerators.addElement(new GF256Poly(field, new int[] { 1 }));
|
||||
}
|
||||
|
||||
private GF256Poly buildGenerator(int degree) {
|
||||
if (degree >= cachedGenerators.size()) {
|
||||
GF256Poly lastGenerator = (GF256Poly) cachedGenerators.elementAt(cachedGenerators.size() - 1);
|
||||
for (int d = cachedGenerators.size(); d <= degree; d++) {
|
||||
GF256Poly nextGenerator = lastGenerator.multiply(new GF256Poly(field, new int[] { 1, field.exp(d - 1) }));
|
||||
cachedGenerators.addElement(nextGenerator);
|
||||
lastGenerator = nextGenerator;
|
||||
}
|
||||
}
|
||||
return (GF256Poly) cachedGenerators.elementAt(degree);
|
||||
}
|
||||
|
||||
public void encode(int[] toEncode, int ecBytes) {
|
||||
int dataBytes = toEncode.length - ecBytes;
|
||||
GF256Poly generator = buildGenerator(ecBytes);
|
||||
int[] infoCoefficients = new int[dataBytes];
|
||||
System.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes);
|
||||
GF256Poly info = new GF256Poly(field, infoCoefficients);
|
||||
info = info.multiplyByMonomial(ecBytes, 1);
|
||||
GF256Poly remainder = info.divide(generator)[1];
|
||||
System.arraycopy(remainder.getCoefficients(), 0, toEncode, dataBytes, ecBytes);
|
||||
}
|
||||
|
||||
}
|
|
@ -39,4 +39,18 @@ abstract class AbstractReedSolomonTestCase extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
static void doTestQRCodeEncoding(int[] dataBytes, int[] expectedECBytes) {
|
||||
int[] toEncode = new int[dataBytes.length + expectedECBytes.length];
|
||||
System.arraycopy(dataBytes, 0, toEncode, 0, dataBytes.length);
|
||||
new ReedSolomonEncoder(GF256.QR_CODE_FIELD).encode(toEncode, expectedECBytes.length);
|
||||
assertArraysEqual(dataBytes, 0, toEncode, 0, dataBytes.length);
|
||||
assertArraysEqual(expectedECBytes, 0, toEncode, dataBytes.length, expectedECBytes.length);
|
||||
}
|
||||
|
||||
private static void assertArraysEqual(int[] expected, int expectedOffset, int[] actual, int actualOffset, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
assertEquals(expected[expectedOffset + i], actual[actualOffset + i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author srowen@google.com (Sean Owen)
|
||||
*/
|
||||
public final class ReedSolomonEncoderQRCodeTestCase extends AbstractReedSolomonTestCase {
|
||||
|
||||
/**
|
||||
* Tests example given in ISO 18004, Annex I
|
||||
*/
|
||||
public void testISO18004Example() {
|
||||
int[] dataBytes = new int[] {
|
||||
0x10, 0x20, 0x0C, 0x56, 0x61, 0x80, 0xEC, 0x11,
|
||||
0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11 };
|
||||
int[] expectedECBytes = new int[] {
|
||||
0xA5, 0x24, 0xD4, 0xC1, 0xED, 0x36, 0xC7, 0x87,
|
||||
0x2C, 0x55 };
|
||||
doTestQRCodeEncoding(dataBytes, expectedECBytes);
|
||||
}
|
||||
|
||||
// Need more tests I am sure
|
||||
|
||||
}
|
Loading…
Reference in a new issue