Updates from sanfordsquires to fix RS decoding for Datamatrix

git-svn-id: https://zxing.googlecode.com/svn/trunk@688 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2008-11-12 12:59:47 +00:00
parent bb52a165d0
commit d56fb38427
7 changed files with 64 additions and 51 deletions

View file

@ -12,5 +12,6 @@ Joseph Wain (Google)
Matthew Schulkind (Google) Matthew Schulkind (Google)
Matt York (LifeMarks) Matt York (LifeMarks)
Paul Hackenberger Paul Hackenberger
sanfordsquires (?)
Sean Owen (Google) Sean Owen (Google)
Vince Francis (LifeMarks) Vince Francis (LifeMarks)

View file

@ -36,6 +36,7 @@ package com.google.zxing.common.reedsolomon;
* *
* @author srowen@google.com (Sean Owen) * @author srowen@google.com (Sean Owen)
* @author William Rucklidge * @author William Rucklidge
* @author sanfordsquires
*/ */
public final class ReedSolomonDecoder { public final class ReedSolomonDecoder {
@ -52,16 +53,15 @@ public final class ReedSolomonDecoder {
* *
* @param received data and error-correction codewords * @param received data and error-correction codewords
* @param twoS number of error-correction codewords available * @param twoS number of error-correction codewords available
* @param dataMatrix if true, then uses a calculation that matches the Data Matrix
* standard rather than the one used in QR Code
* @throws ReedSolomonException if decoding fails for any reason * @throws ReedSolomonException if decoding fails for any reason
*/ */
public void decode(int[] received, int twoS, boolean dataMatrix) throws ReedSolomonException { public void decode(int[] received, int twoS) throws ReedSolomonException {
GF256Poly poly = new GF256Poly(field, received); GF256Poly poly = new GF256Poly(field, received);
int[] syndromeCoefficients = new int[twoS]; int[] syndromeCoefficients = new int[twoS];
boolean dataMatrix = field.equals(GF256.DATA_MATRIX_FIELD);
boolean noError = true; boolean noError = true;
for (int i = 0; i < twoS; i++) { for (int i = 0; i < twoS; i++) {
// This difference in syndrome calculation appears to be correct, but then causes issues below // Thanks to sanfordsquires for this fix:
int eval = poly.evaluateAt(field.exp(dataMatrix ? i + 1 : i)); int eval = poly.evaluateAt(field.exp(dataMatrix ? i + 1 : i));
syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval; syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval;
if (eval != 0) { if (eval != 0) {
@ -72,19 +72,17 @@ public final class ReedSolomonDecoder {
return; return;
} }
GF256Poly syndrome = new GF256Poly(field, syndromeCoefficients); GF256Poly syndrome = new GF256Poly(field, syndromeCoefficients);
if (dataMatrix) {
// TODO Not clear this is correct for DataMatrix, but it gives almost-correct behavior;
// works except when number of errors is the maximum allowable.
syndrome = syndrome.multiply(field.buildMonomial(1, 1));
}
GF256Poly[] sigmaOmega = GF256Poly[] sigmaOmega =
runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS); runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
GF256Poly sigma = sigmaOmega[0]; GF256Poly sigma = sigmaOmega[0];
GF256Poly omega = sigmaOmega[1]; GF256Poly omega = sigmaOmega[1];
int[] errorLocations = findErrorLocations(sigma); int[] errorLocations = findErrorLocations(sigma);
int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations); int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix);
for (int i = 0; i < errorLocations.length; i++) { for (int i = 0; i < errorLocations.length; i++) {
int position = received.length - 1 - field.log(errorLocations[i]); int position = received.length - 1 - field.log(errorLocations[i]);
if (position < 0) {
throw new ReedSolomonException("Bad error location");
}
received[position] = GF256.addOrSubtract(received[position], errorMagnitudes[i]); received[position] = GF256.addOrSubtract(received[position], errorMagnitudes[i]);
} }
} }
@ -165,7 +163,7 @@ public final class ReedSolomonDecoder {
return result; return result;
} }
private int[] findErrorMagnitudes(GF256Poly errorEvaluator, int[] errorLocations) { private int[] findErrorMagnitudes(GF256Poly errorEvaluator, int[] errorLocations, boolean dataMatrix) {
// 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];
@ -180,6 +178,10 @@ public final class ReedSolomonDecoder {
} }
result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse),
field.inverse(denominator)); field.inverse(denominator));
// Thanks to sanfordsquires for this fix:
if (dataMatrix) {
result[i] = field.multiply(result[i], xiInverse);
}
} }
return result; return result;
} }

View file

@ -118,7 +118,7 @@ public final class Decoder {
} }
int numECCodewords = codewordBytes.length - numDataCodewords; int numECCodewords = codewordBytes.length - numDataCodewords;
try { try {
rsDecoder.decode(codewordsInts, numECCodewords, true); rsDecoder.decode(codewordsInts, numECCodewords);
} catch (ReedSolomonException rse) { } catch (ReedSolomonException rse) {
throw new ReaderException(rse.toString()); throw new ReaderException(rse.toString());
} }

View file

@ -118,7 +118,7 @@ public final class Decoder {
} }
int numECCodewords = codewordBytes.length - numDataCodewords; int numECCodewords = codewordBytes.length - numDataCodewords;
try { try {
rsDecoder.decode(codewordsInts, numECCodewords, false); rsDecoder.decode(codewordsInts, numECCodewords);
} catch (ReedSolomonException rse) { } catch (ReedSolomonException rse) {
throw new ReaderException(rse.toString()); throw new ReaderException(rse.toString());
} }

View file

@ -0,0 +1,42 @@
/*
* 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 junit.framework.TestCase;
import java.util.BitSet;
import java.util.Random;
/**
* @author srowen@google.com (Sean Owen)
*/
abstract class AbstractReedSolomonTestCase extends TestCase {
static void corrupt(int[] received, int howMany, Random random) {
BitSet corrupted = new BitSet(received.length);
for (int j = 0; j < howMany; j++) {
int location = random.nextInt(received.length);
if (corrupted.get(location)) {
j--;
} else {
corrupted.set(location);
received[location] = (received[location] + 1 + random.nextInt(255)) & 0xFF;
}
}
}
}

View file

@ -16,15 +16,13 @@
package com.google.zxing.common.reedsolomon; package com.google.zxing.common.reedsolomon;
import junit.framework.TestCase;
import java.util.BitSet;
import java.util.Random; import java.util.Random;
/** /**
* @author srowen@google.com (Sean Owen) * @author srowen@google.com (Sean Owen)
* @author sanfordsquires
*/ */
public final class ReedSolomonDecoderDataMatrixTestCase extends TestCase { public final class ReedSolomonDecoderDataMatrixTestCase extends AbstractReedSolomonTestCase {
private static final int[] DM_CODE_TEST = { 142, 164, 186 }; private static final int[] DM_CODE_TEST = { 142, 164, 186 };
private static final int[] DM_CODE_TEST_WITH_EC = { 142, 164, 186, 114, 25, 5, 88, 102 }; private static final int[] DM_CODE_TEST_WITH_EC = { 142, 164, 186, 114, 25, 5, 88, 102 };
@ -54,8 +52,7 @@ public final class ReedSolomonDecoderDataMatrixTestCase extends TestCase {
Random random = new Random(0xDEADBEEFL); Random random = new Random(0xDEADBEEFL);
for (int i = 0; i < DM_CODE_TEST.length; i++) { // # iterations is kind of arbitrary for (int i = 0; i < DM_CODE_TEST.length; i++) { // # iterations is kind of arbitrary
System.arraycopy(DM_CODE_TEST_WITH_EC, 0, received, 0, received.length); System.arraycopy(DM_CODE_TEST_WITH_EC, 0, received, 0, received.length);
// TODO we aren't testing max errors really since there is a known bug here corrupt(received, DM_CODE_CORRECTABLE, random);
corrupt(received, DM_CODE_CORRECTABLE - 1, random);
checkQRRSDecode(received); checkQRRSDecode(received);
} }
} }
@ -74,23 +71,10 @@ public final class ReedSolomonDecoderDataMatrixTestCase extends TestCase {
} }
private void checkQRRSDecode(int[] received) throws ReedSolomonException { private void checkQRRSDecode(int[] received) throws ReedSolomonException {
dmRSDecoder.decode(received, 2 * DM_CODE_CORRECTABLE, true); dmRSDecoder.decode(received, 2 * DM_CODE_CORRECTABLE);
for (int i = 0; i < DM_CODE_TEST.length; i++) { for (int i = 0; i < DM_CODE_TEST.length; i++) {
assertEquals(received[i], DM_CODE_TEST[i]); assertEquals(received[i], DM_CODE_TEST[i]);
} }
} }
private static void corrupt(int[] received, int howMany, Random random) {
BitSet corrupted = new BitSet(received.length);
for (int j = 0; j < howMany; j++) {
int location = random.nextInt(received.length);
if (corrupted.get(location)) {
j--;
} else {
corrupted.set(location);
int newByte = random.nextInt(256);
received[location] = newByte;
}
}
}
} }

View file

@ -16,15 +16,12 @@
package com.google.zxing.common.reedsolomon; package com.google.zxing.common.reedsolomon;
import junit.framework.TestCase;
import java.util.BitSet;
import java.util.Random; import java.util.Random;
/** /**
* @author srowen@google.com (Sean Owen) * @author srowen@google.com (Sean Owen)
*/ */
public final class ReedSolomonDecoderQRCodeTestCase extends TestCase { public final class ReedSolomonDecoderQRCodeTestCase extends AbstractReedSolomonTestCase {
/** See ISO 18004, Appendix I, from which this example is taken. */ /** See ISO 18004, Appendix I, from which this example is taken. */
private static final int[] QR_CODE_TEST = private static final int[] QR_CODE_TEST =
@ -79,23 +76,10 @@ public final class ReedSolomonDecoderQRCodeTestCase extends TestCase {
} }
private void checkQRRSDecode(int[] received) throws ReedSolomonException { private void checkQRRSDecode(int[] received) throws ReedSolomonException {
qrRSDecoder.decode(received, 2*QR_CODE_CORRECTABLE, false); qrRSDecoder.decode(received, 2*QR_CODE_CORRECTABLE);
for (int i = 0; i < QR_CODE_TEST.length; i++) { for (int i = 0; i < QR_CODE_TEST.length; i++) {
assertEquals(received[i], QR_CODE_TEST[i]); assertEquals(received[i], QR_CODE_TEST[i]);
} }
} }
private static void corrupt(int[] received, int howMany, Random random) {
BitSet corrupted = new BitSet(received.length);
for (int j = 0; j < howMany; j++) {
int location = random.nextInt(received.length);
if (corrupted.get(location)) {
j--;
} else {
corrupted.set(location);
int newByte = random.nextInt(256);
received[location] = newByte;
}
}
}
} }