mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Related to Issue 205, but not the direct issue: read both copies of the format info and use both in determining the right one. This avoids a close, but incorrect first match throwing off the decoding. Also fix creating an image from ByteMatrix -- was inverted
git-svn-id: https://zxing.googlecode.com/svn/trunk@1226 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
5afa0fd861
commit
508697a318
|
@ -54,36 +54,31 @@ final class BitMatrixParser {
|
|||
}
|
||||
|
||||
// Read top-left format info bits
|
||||
int formatInfoBits = 0;
|
||||
int formatInfoBits1 = 0;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
formatInfoBits = copyBit(i, 8, formatInfoBits);
|
||||
formatInfoBits1 = copyBit(i, 8, formatInfoBits1);
|
||||
}
|
||||
// .. and skip a bit in the timing pattern ...
|
||||
formatInfoBits = copyBit(7, 8, formatInfoBits);
|
||||
formatInfoBits = copyBit(8, 8, formatInfoBits);
|
||||
formatInfoBits = copyBit(8, 7, formatInfoBits);
|
||||
formatInfoBits1 = copyBit(7, 8, formatInfoBits1);
|
||||
formatInfoBits1 = copyBit(8, 8, formatInfoBits1);
|
||||
formatInfoBits1 = copyBit(8, 7, formatInfoBits1);
|
||||
// .. and skip a bit in the timing pattern ...
|
||||
for (int j = 5; j >= 0; j--) {
|
||||
formatInfoBits = copyBit(8, j, formatInfoBits);
|
||||
formatInfoBits1 = copyBit(8, j, formatInfoBits1);
|
||||
}
|
||||
|
||||
parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
|
||||
if (parsedFormatInfo != null) {
|
||||
return parsedFormatInfo;
|
||||
}
|
||||
|
||||
// Hmm, failed. Try the top-right/bottom-left pattern
|
||||
// Read the top-right/bottom-left pattern too
|
||||
int dimension = bitMatrix.getDimension();
|
||||
formatInfoBits = 0;
|
||||
int formatInfoBits2 = 0;
|
||||
int iMin = dimension - 8;
|
||||
for (int i = dimension - 1; i >= iMin; i--) {
|
||||
formatInfoBits = copyBit(i, 8, formatInfoBits);
|
||||
formatInfoBits2 = copyBit(i, 8, formatInfoBits2);
|
||||
}
|
||||
for (int j = dimension - 7; j < dimension; j++) {
|
||||
formatInfoBits = copyBit(8, j, formatInfoBits);
|
||||
formatInfoBits2 = copyBit(8, j, formatInfoBits2);
|
||||
}
|
||||
|
||||
parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits);
|
||||
parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits1, formatInfoBits2);
|
||||
if (parsedFormatInfo != null) {
|
||||
return parsedFormatInfo;
|
||||
}
|
||||
|
|
|
@ -96,37 +96,48 @@ final class FormatInformation {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param maskedFormatInfo format info indicator, with mask still applied
|
||||
* @param maskedFormatInfo1 format info indicator, with mask still applied
|
||||
* @param maskedFormatInfo2 second copy of same info; both are checked at the same time
|
||||
* to establish best match
|
||||
* @return information about the format it specifies, or <code>null</code>
|
||||
* if doesn't seem to match any known pattern
|
||||
*/
|
||||
static FormatInformation decodeFormatInformation(int maskedFormatInfo) {
|
||||
FormatInformation formatInfo = doDecodeFormatInformation(maskedFormatInfo);
|
||||
static FormatInformation decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) {
|
||||
FormatInformation formatInfo = doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2);
|
||||
if (formatInfo != null) {
|
||||
return formatInfo;
|
||||
}
|
||||
// Should return null, but, some QR codes apparently
|
||||
// do not mask this info. Try again by actually masking the pattern
|
||||
// first
|
||||
return doDecodeFormatInformation(maskedFormatInfo ^ FORMAT_INFO_MASK_QR);
|
||||
return doDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR,
|
||||
maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR);
|
||||
}
|
||||
|
||||
private static FormatInformation doDecodeFormatInformation(int maskedFormatInfo) {
|
||||
private static FormatInformation doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) {
|
||||
// Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
|
||||
int bestDifference = Integer.MAX_VALUE;
|
||||
int bestFormatInfo = 0;
|
||||
for (int i = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++) {
|
||||
int[] decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i];
|
||||
int targetInfo = decodeInfo[0];
|
||||
if (targetInfo == maskedFormatInfo) {
|
||||
if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2) {
|
||||
// Found an exact match
|
||||
return new FormatInformation(decodeInfo[1]);
|
||||
}
|
||||
int bitsDifference = numBitsDiffering(maskedFormatInfo, targetInfo);
|
||||
int bitsDifference = numBitsDiffering(maskedFormatInfo1, targetInfo);
|
||||
if (bitsDifference < bestDifference) {
|
||||
bestFormatInfo = decodeInfo[1];
|
||||
bestDifference = bitsDifference;
|
||||
}
|
||||
if (maskedFormatInfo1 != maskedFormatInfo2) {
|
||||
// also try the other option
|
||||
bitsDifference = numBitsDiffering(maskedFormatInfo2, targetInfo);
|
||||
if (bitsDifference < bestDifference) {
|
||||
bestFormatInfo = decodeInfo[1];
|
||||
bestDifference = bitsDifference;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
|
||||
// differing means we found a match
|
||||
|
|
|
@ -35,17 +35,34 @@ public final class FormatInformationTestCase extends TestCase {
|
|||
|
||||
public void testDecode() {
|
||||
// Normal case
|
||||
FormatInformation expected = FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO);
|
||||
FormatInformation expected =
|
||||
FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
|
||||
assertEquals((byte) 0x07, expected.getDataMask());
|
||||
assertEquals(ErrorCorrectionLevel.Q, expected.getErrorCorrectionLevel());
|
||||
assertSame(ErrorCorrectionLevel.Q, expected.getErrorCorrectionLevel());
|
||||
// where the code forgot the mask!
|
||||
assertEquals(expected, FormatInformation.decodeFormatInformation(UNMASKED_TEST_FORMAT_INFO));
|
||||
assertEquals(expected,
|
||||
FormatInformation.decodeFormatInformation(UNMASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO));
|
||||
}
|
||||
|
||||
public void testDecodeWithBitDifference() {
|
||||
FormatInformation expected =
|
||||
FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
|
||||
// 1,2,3,4 bits difference
|
||||
assertEquals(expected, FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x01));
|
||||
assertEquals(expected, FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x03));
|
||||
assertEquals(expected, FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x07));
|
||||
assertNull(FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x0F));
|
||||
assertEquals(expected, FormatInformation.decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x01, MASKED_TEST_FORMAT_INFO ^ 0x01));
|
||||
assertEquals(expected, FormatInformation.decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x03));
|
||||
assertEquals(expected, FormatInformation.decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x07, MASKED_TEST_FORMAT_INFO ^ 0x07));
|
||||
assertNull(FormatInformation.decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x0F, MASKED_TEST_FORMAT_INFO ^ 0x0F));
|
||||
}
|
||||
|
||||
public void testDecodeWithMisread() {
|
||||
FormatInformation expected =
|
||||
FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
|
||||
assertEquals(expected, FormatInformation.decodeFormatInformation(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x0F));
|
||||
}
|
||||
|
||||
}
|
|
@ -68,7 +68,7 @@ public final class MatrixToImageWriter {
|
|||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
image.setRGB(x, y, matrix.get(x, y) == 0 ? BLACK : WHITE);
|
||||
image.setRGB(x, y, matrix.get(x, y) == 0 ? WHITE : BLACK);
|
||||
}
|
||||
}
|
||||
return image;
|
||||
|
|
Loading…
Reference in a new issue