mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 12:22:34 +00:00
non passing aztec decoder port
This commit is contained in:
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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.aztec.decoder;
|
||||
|
||||
import com.google.zxing.aztec.encoder.EncoderTest;
|
||||
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.RXingResultPoint;
|
||||
import com.google.zxing.aztec.AztecDetectorRXingResult;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.DecoderRXingResult;
|
||||
import org.junit.Test;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
* Tests {@link Decoder}.
|
||||
*/
|
||||
public final class DecoderTest extends Assert {
|
||||
|
||||
private static final RXingResultPoint[] NO_POINTS = new RXingResultPoint[0];
|
||||
|
||||
@Test
|
||||
public void testHighLevelDecode() throws FormatException {
|
||||
// no ECI codes
|
||||
testHighLevelDecodeString("A. b.",
|
||||
// 'A' P/S '. ' L/L b D/L '.'
|
||||
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X");
|
||||
|
||||
// initial ECI code 26 (switch to UTF-8)
|
||||
testHighLevelDecodeString("Ça",
|
||||
// P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
|
||||
"..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.");
|
||||
|
||||
// initial character without ECI (must be interpreted as ISO_8859_1)
|
||||
// followed by ECI code 26 (= UTF-8) and UTF-8 text
|
||||
testHighLevelDecodeString("±Ça",
|
||||
// B/S 1 0xb1 P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
|
||||
"XXXXX ....X X.XX...X ..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.");
|
||||
|
||||
// GS1 data
|
||||
testHighLevelDecodeString("101233742",
|
||||
// P/S FLG(n) 0 D/L 1 0 1 2 3 P/S FLG(n) 0 3 7 4 2
|
||||
"..... ..... ... XXXX. ..XX ..X. ..XX .X.. .X.X .... ..... ... .X.X X..X .XX. .X..");
|
||||
}
|
||||
|
||||
private static void testHighLevelDecodeString(String expectedString, String b) throws FormatException {
|
||||
BitArray bits = EncoderTest.toBitArray(EncoderTest.stripSpace(b));
|
||||
assertEquals("highLevelDecode() failed for input bits: " + b,
|
||||
expectedString, Decoder.highLevelDecode(EncoderTest.toBooleanArray(bits)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAztecRXingResult() throws FormatException {
|
||||
BitMatrix matrix = BitMatrix.parse(
|
||||
"X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X \n" +
|
||||
" X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X \n",
|
||||
"X ", " ");
|
||||
AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, false, 30, 2);
|
||||
DecoderRXingResult result = new Decoder().decode(r);
|
||||
assertEquals("88888TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT", result.getText());
|
||||
assertArrayEquals(
|
||||
new byte[] {-11, 85, 85, 117, 107, 90, -42, -75, -83, 107,
|
||||
90, -42, -75, -83, 107, 90, -42, -75, -83, 107,
|
||||
90, -42, -80},
|
||||
result.getRawBytes());
|
||||
assertEquals(180, result.getNumBits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAztecRXingResultECI() throws FormatException {
|
||||
BitMatrix matrix = BitMatrix.parse(
|
||||
" X X X X X X \n" +
|
||||
" X X X X X X X X X X X X \n" +
|
||||
" X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X \n" +
|
||||
" X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X \n" +
|
||||
" X X X X X X X X X \n" +
|
||||
"X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X \n" +
|
||||
" X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X \n" +
|
||||
" X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X \n",
|
||||
"X ", " ");
|
||||
AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, false, 15, 1);
|
||||
DecoderRXingResult result = new Decoder().decode(r);
|
||||
assertEquals("Français", result.getText());
|
||||
}
|
||||
|
||||
@Test(expected = FormatException.class)
|
||||
public void testDecodeTooManyErrors() throws FormatException {
|
||||
BitMatrix matrix = BitMatrix.parse(""
|
||||
+ "X X . X . . . X X . . . X . . X X X . X . X X X X X . \n"
|
||||
+ "X X . . X X . . . . . X X . . . X X . . . X . X . . X \n"
|
||||
+ "X . . . X X . . X X X . X X . X X X X . X X . . X . . \n"
|
||||
+ ". . . . X . X X . . X X . X X . X . X X X X . X . . X \n"
|
||||
+ "X X X . . X X X X X . . . . . X X . . . X . X . X . X \n"
|
||||
+ "X X . . . . . . . . X . . . X . X X X . X . . X . . . \n"
|
||||
+ "X X . . X . . . . . X X . . . . . X . . . . X . . X X \n"
|
||||
+ ". . . X . X . X . . . . . X X X X X X . . . . . . X X \n"
|
||||
+ "X . . . X . X X X X X X . . X X X . X . X X X X X X . \n"
|
||||
+ "X . . X X X . X X X X X X X X X X X X X . . . X . X X \n"
|
||||
+ ". . . . X X . . . X . . . . . . . X X . . . X X . X . \n"
|
||||
+ ". . . X X X . . X X . X X X X X . X . . X . . . . . . \n"
|
||||
+ "X . . . . X . X . X . X . . . X . X . X X . X X . X X \n"
|
||||
+ "X . X . . X . X . X . X . X . X . X . . . . . X . X X \n"
|
||||
+ "X . X X X . . X . X . X . . . X . X . X X X . . . X X \n"
|
||||
+ "X X X X X X X X . X . X X X X X . X . X . X . X X X . \n"
|
||||
+ ". . . . . . . X . X . . . . . . . X X X X . . . X X X \n"
|
||||
+ "X X . . X . . X . X X X X X X X X X X X X X . . X . X \n"
|
||||
+ "X X X . X X X X . . X X X X . . X . . . . X . . X X X \n"
|
||||
+ ". . . . X . X X X . . . . X X X X . . X X X X . . . . \n"
|
||||
+ ". . X . . X . X . . . X . X X . X X . X . . . X . X . \n"
|
||||
+ "X X . . X . . X X X X X X X . . X . X X X X X X X . . \n"
|
||||
+ "X . X X . . X X . . . . . X . . . . . . X X . X X X . \n"
|
||||
+ "X . . X X . . X X . X . X . . . . X . X . . X . . X . \n"
|
||||
+ "X . X . X . . X . X X X X X X X X . X X X X . . X X . \n"
|
||||
+ "X X X X . . . X . . X X X . X X . . X . . . . X X X . \n"
|
||||
+ "X X . X . X . . . X . X . . . . X X . X . . X X . . . \n",
|
||||
"X ", ". ");
|
||||
AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, true, 16, 4);
|
||||
new Decoder().decode(r);
|
||||
}
|
||||
|
||||
@Test(expected = FormatException.class)
|
||||
public void testDecodeTooManyErrors2() throws FormatException {
|
||||
BitMatrix matrix = BitMatrix.parse(""
|
||||
+ ". X X . . X . X X . . . X . . X X X . . . X X . X X . \n"
|
||||
+ "X X . X X . . X . . . X X . . . X X . X X X . X . X X \n"
|
||||
+ ". . . . X . . . X X X . X X . X X X X . X X . . X . . \n"
|
||||
+ "X . X X . . X . . . X X . X X . X . X X . . . . . X . \n"
|
||||
+ "X X . X . . X . X X . . . . . X X . . . . . X . . . X \n"
|
||||
+ "X . . X . . . . . . X . . . X . X X X X X X X . . . X \n"
|
||||
+ "X . . X X . . X . . X X . . . . . X . . . . . X X X . \n"
|
||||
+ ". . X X X X . X . . . . . X X X X X X . . . . . . X X \n"
|
||||
+ "X . . . X . X X X X X X . . X X X . X . X X X X X X . \n"
|
||||
+ "X . . X X X . X X X X X X X X X X X X X . . . X . X X \n"
|
||||
+ ". . . . X X . . . X . . . . . . . X X . . . X X . X . \n"
|
||||
+ ". . . X X X . . X X . X X X X X . X . . X . . . . . . \n"
|
||||
+ "X . . . . X . X . X . X . . . X . X . X X . X X . X X \n"
|
||||
+ "X . X . . X . X . X . X . X . X . X . . . . . X . X X \n"
|
||||
+ "X . X X X . . X . X . X . . . X . X . X X X . . . X X \n"
|
||||
+ "X X X X X X X X . X . X X X X X . X . X . X . X X X . \n"
|
||||
+ ". . . . . . . X . X . . . . . . . X X X X . . . X X X \n"
|
||||
+ "X X . . X . . X . X X X X X X X X X X X X X . . X . X \n"
|
||||
+ "X X X . X X X X . . X X X X . . X . . . . X . . X X X \n"
|
||||
+ ". . X X X X X . X . . . . X X X X . . X X X . X . X . \n"
|
||||
+ ". . X X . X . X . . . X . X X . X X . . . . X X . . . \n"
|
||||
+ "X . . . X . X . X X X X X X . . X . X X X X X . X . . \n"
|
||||
+ ". X . . . X X X . . . . . X . . . . . X X X X X . X . \n"
|
||||
+ "X . . X . X X X X . X . X . . . . X . X X . X . . X . \n"
|
||||
+ "X . . . X X . X . X X X X X X X X . X X X X . . X X . \n"
|
||||
+ ". X X X X . . X . . X X X . X X . . X . . . . X X X . \n"
|
||||
+ "X X . . . X X . . X . X . . . . X X . X . . X . X . X \n",
|
||||
"X ", ". ");
|
||||
AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, true, 16, 4);
|
||||
new Decoder().decode(r);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawBytes() {
|
||||
boolean[] bool0 = {};
|
||||
boolean[] bool1 = { true };
|
||||
boolean[] bool7 = { true, false, true, false, true, false, true };
|
||||
boolean[] bool8 = { true, false, true, false, true, false, true, false };
|
||||
boolean[] bool9 = { true, false, true, false, true, false, true, false,
|
||||
true };
|
||||
boolean[] bool16 = { false, true, true, false, false, false, true, true,
|
||||
true, true, false, false, false, false, false, true };
|
||||
byte[] byte0 = {};
|
||||
byte[] byte1 = { -128 };
|
||||
byte[] byte7 = { -86 };
|
||||
byte[] byte8 = { -86 };
|
||||
byte[] byte9 = { -86, -128 };
|
||||
byte[] byte16 = { 99, -63 };
|
||||
|
||||
assertArrayEquals(byte0, Decoder.convertBoolArrayToByteArray(bool0));
|
||||
assertArrayEquals(byte1, Decoder.convertBoolArrayToByteArray(bool1));
|
||||
assertArrayEquals(byte7, Decoder.convertBoolArrayToByteArray(bool7));
|
||||
assertArrayEquals(byte8, Decoder.convertBoolArrayToByteArray(bool8));
|
||||
assertArrayEquals(byte9, Decoder.convertBoolArrayToByteArray(bool9));
|
||||
assertArrayEquals(byte16, Decoder.convertBoolArrayToByteArray(bool16));
|
||||
}
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.aztec.detector;
|
||||
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.aztec.AztecDetectorRXingResult;
|
||||
import com.google.zxing.aztec.decoder.Decoder;
|
||||
import com.google.zxing.aztec.detector.Detector.Point;
|
||||
import com.google.zxing.aztec.encoder.AztecCode;
|
||||
import com.google.zxing.aztec.encoder.Encoder;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.DecoderRXingResult;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Tests for the Detector
|
||||
*
|
||||
* @author Frank Yellin
|
||||
*/
|
||||
public final class DetectorTest extends Assert {
|
||||
|
||||
@Test
|
||||
public void testErrorInParameterLocatorZeroZero() throws Exception {
|
||||
// Layers=1, CodeWords=1. So the parameter info and its Reed-Solomon info
|
||||
// will be completely zero!
|
||||
testErrorInParameterLocator("X");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorInParameterLocatorCompact() throws Exception {
|
||||
testErrorInParameterLocator("This is an example Aztec symbol for Wikipedia.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorInParameterLocatorNotCompact() throws Exception {
|
||||
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz";
|
||||
testErrorInParameterLocator(alphabet + alphabet + alphabet);
|
||||
}
|
||||
|
||||
// Test that we can tolerate errors in the parameter locator bits
|
||||
private static void testErrorInParameterLocator(String data) throws Exception {
|
||||
AztecCode aztec = Encoder.encode(data, 25, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||
Random random = new Random(aztec.getMatrix().hashCode()); // pseudo-random, but deterministic
|
||||
int layers = aztec.getLayers();
|
||||
boolean compact = aztec.isCompact();
|
||||
List<Point> orientationPoints = getOrientationPoints(aztec);
|
||||
for (boolean isMirror : new boolean[] { false, true }) {
|
||||
for (BitMatrix matrix : getRotations(aztec.getMatrix())) {
|
||||
// Systematically try every possible 1- and 2-bit error.
|
||||
for (int error1 = 0; error1 < orientationPoints.size(); error1++) {
|
||||
for (int error2 = error1; error2 < orientationPoints.size(); error2++) {
|
||||
BitMatrix copy = isMirror ? transpose(matrix) : clone(matrix);
|
||||
copy.flip(orientationPoints.get(error1).getX(), orientationPoints.get(error1).getY());
|
||||
if (error2 > error1) {
|
||||
// if error2 == error1, we only test a single error
|
||||
copy.flip(orientationPoints.get(error2).getX(), orientationPoints.get(error2).getY());
|
||||
}
|
||||
// The detector doesn't seem to work when matrix bits are only 1x1. So magnify.
|
||||
AztecDetectorRXingResult r = new Detector(makeLarger(copy, 3)).detect(isMirror);
|
||||
assertNotNull(r);
|
||||
assertEquals(r.getNbLayers(), layers);
|
||||
assertEquals(r.isCompact(), compact);
|
||||
DecoderRXingResult res = new Decoder().decode(r);
|
||||
assertEquals(data, res.getText());
|
||||
}
|
||||
}
|
||||
// Try a few random three-bit errors;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
BitMatrix copy = clone(matrix);
|
||||
Collection<Integer> errors = new TreeSet<>();
|
||||
while (errors.size() < 3) {
|
||||
// Quick and dirty way of getting three distinct integers between 1 and n.
|
||||
errors.add(random.nextInt(orientationPoints.size()));
|
||||
}
|
||||
for (int error : errors) {
|
||||
copy.flip(orientationPoints.get(error).getX(), orientationPoints.get(error).getY());
|
||||
}
|
||||
try {
|
||||
new Detector(makeLarger(copy, 3)).detect(false);
|
||||
fail("Should not reach here");
|
||||
} catch (NotFoundException expected) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Zooms a bit matrix so that each bit is factor x factor
|
||||
private static BitMatrix makeLarger(BitMatrix input, int factor) {
|
||||
int width = input.getWidth();
|
||||
BitMatrix output = new BitMatrix(width * factor);
|
||||
for (int inputY = 0; inputY < width; inputY++) {
|
||||
for (int inputX = 0; inputX < width; inputX++) {
|
||||
if (input.get(inputX, inputY)) {
|
||||
output.setRegion(inputX * factor, inputY * factor, factor, factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// Returns a list of the four rotations of the BitMatrix.
|
||||
private static Iterable<BitMatrix> getRotations(BitMatrix matrix0) {
|
||||
BitMatrix matrix90 = rotateRight(matrix0);
|
||||
BitMatrix matrix180 = rotateRight(matrix90);
|
||||
BitMatrix matrix270 = rotateRight(matrix180);
|
||||
return Arrays.asList(matrix0, matrix90, matrix180, matrix270);
|
||||
}
|
||||
|
||||
// Rotates a square BitMatrix to the right by 90 degrees
|
||||
private static BitMatrix rotateRight(BitMatrix input) {
|
||||
int width = input.getWidth();
|
||||
BitMatrix result = new BitMatrix(width);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < width; y++) {
|
||||
if (input.get(x,y)) {
|
||||
result.set(y, width - x - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns the transpose of a bit matrix, which is equivalent to rotating the
|
||||
// matrix to the right, and then flipping it left-to-right
|
||||
private static BitMatrix transpose(BitMatrix input) {
|
||||
int width = input.getWidth();
|
||||
BitMatrix result = new BitMatrix(width);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < width; y++) {
|
||||
if (input.get(x, y)) {
|
||||
result.set(y, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static BitMatrix clone(BitMatrix input) {
|
||||
int width = input.getWidth();
|
||||
BitMatrix result = new BitMatrix(width);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < width; y++) {
|
||||
if (input.get(x,y)) {
|
||||
result.set(x,y);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<Point> getOrientationPoints(AztecCode code) {
|
||||
int center = code.getMatrix().getWidth() / 2;
|
||||
int offset = code.isCompact() ? 5 : 7;
|
||||
List<Point> result = new ArrayList<>();
|
||||
for (int xSign = -1; xSign <= 1; xSign += 2) {
|
||||
for (int ySign = -1; ySign <= 1; ySign += 2) {
|
||||
result.add(new Point(center + xSign * offset, center + ySign * offset));
|
||||
result.add(new Point(center + xSign * (offset - 1), center + ySign * offset));
|
||||
result.add(new Point(center + xSign * offset, center + ySign * (offset - 1)));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,603 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 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.aztec.encoder;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.RXingResultPoint;
|
||||
import com.google.zxing.aztec.AztecDetectorRXingResult;
|
||||
import com.google.zxing.aztec.AztecWriter;
|
||||
import com.google.zxing.aztec.decoder.Decoder;
|
||||
import com.google.zxing.common.BitArray;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.DecoderRXingResult;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Aztec 2D generator unit tests.
|
||||
*
|
||||
* @author Rustam Abdullaev
|
||||
* @author Frank Yellin
|
||||
*/
|
||||
public final class EncoderTest extends Assert {
|
||||
|
||||
private static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1;
|
||||
private static final Charset UTF_8 = StandardCharsets.UTF_8;
|
||||
private static final Charset SHIFT_JIS = Charset.forName("Shift_JIS");
|
||||
private static final Charset ISO_8859_15 = Charset.forName("ISO-8859-15");
|
||||
private static final Charset WINDOWS_1252 = Charset.forName("Windows-1252");
|
||||
|
||||
private static final Pattern DOTX = Pattern.compile("[^.X]");
|
||||
private static final Pattern SPACES = Pattern.compile("\\s+");
|
||||
private static final RXingResultPoint[] NO_POINTS = new RXingResultPoint[0];
|
||||
|
||||
// real life tests
|
||||
|
||||
@Test
|
||||
public void testEncode1() {
|
||||
testEncode("This is an example Aztec symbol for Wikipedia.", true, 3,
|
||||
"X X X X X X X X \n" +
|
||||
"X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X \n" +
|
||||
" X X X \n" +
|
||||
" X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X \n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncode2() {
|
||||
testEncode("Aztec Code is a public domain 2D matrix barcode symbology" +
|
||||
" of nominally square symbols built on a square grid with a " +
|
||||
"distinctive square bullseye pattern at their center.", false, 6,
|
||||
" X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X X X X X X X X X \n" +
|
||||
" X X X X X X X X X X X X X X X X \n" +
|
||||
"X X X X X X X X X X X X X \n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAztecWriter() throws Exception {
|
||||
testWriter("Espa\u00F1ol", null, 25, true, 1); // Without ECI (implicit ISO-8859-1)
|
||||
testWriter("Espa\u00F1ol", ISO_8859_1, 25, true, 1); // Explicit ISO-8859-1
|
||||
testWriter("\u20AC 1 sample data.", WINDOWS_1252, 25, true, 2); // ISO-8859-1 can't encode Euro; Windows-1252 can
|
||||
testWriter("\u20AC 1 sample data.", ISO_8859_15, 25, true, 2);
|
||||
testWriter("\u20AC 1 sample data.", UTF_8, 25, true, 2);
|
||||
testWriter("\u20AC 1 sample data.", UTF_8, 100, true, 3);
|
||||
testWriter("\u20AC 1 sample data.", UTF_8, 300, true, 4);
|
||||
testWriter("\u20AC 1 sample data.", UTF_8, 500, false, 5);
|
||||
testWriter("The capital of Japan is named \u6771\u4EAC.", SHIFT_JIS, 25, true, 3);
|
||||
// Test AztecWriter defaults
|
||||
String data = "In ut magna vel mauris malesuada";
|
||||
AztecWriter writer = new AztecWriter();
|
||||
BitMatrix matrix = writer.encode(data, BarcodeFormat.AZTEC, 0, 0);
|
||||
AztecCode aztec = Encoder.encode(data,
|
||||
Encoder.DEFAULT_EC_PERCENT, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||
BitMatrix expectedMatrix = aztec.getMatrix();
|
||||
assertEquals(matrix, expectedMatrix);
|
||||
}
|
||||
|
||||
// synthetic tests (encode-decode round-trip)
|
||||
|
||||
@Test
|
||||
public void testEncodeDecode1() throws Exception {
|
||||
testEncodeDecode("Abc123!", true, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeDecode2() throws Exception {
|
||||
testEncodeDecode("Lorem ipsum. http://test/", true, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeDecode3() throws Exception {
|
||||
testEncodeDecode("AAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAAN", true, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeDecode4() throws Exception {
|
||||
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384", true, 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeDecode5() throws Exception {
|
||||
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384756<>/?abc"
|
||||
+ "Four score and seven our forefathers brought forth", false, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeDecode10() throws Exception {
|
||||
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
|
||||
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
|
||||
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
|
||||
" auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla" +
|
||||
" ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id" +
|
||||
" elementum sapien dolor et diam.", false, 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeDecode23() throws Exception {
|
||||
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
|
||||
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
|
||||
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
|
||||
" auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla" +
|
||||
" ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id" +
|
||||
" elementum sapien dolor et diam. Donec ac nunc sodales elit placerat eleifend." +
|
||||
" Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra fringilla, risus" +
|
||||
" justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo diam, lobortis eu" +
|
||||
" tristique ac, p.In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus" +
|
||||
" quis diam cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec" +
|
||||
" laoreet rutrum est, nec convallis mauris condimentum sit amet. Phasellus gravida," +
|
||||
" justo et congue auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec" +
|
||||
" lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar" +
|
||||
" nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit placerat" +
|
||||
" eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra" +
|
||||
" fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo" +
|
||||
" diam, lobortis eu tristique ac, p. In ut magna vel mauris malesuada dictum. Nulla" +
|
||||
" ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum" +
|
||||
" sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet." +
|
||||
" Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit" +
|
||||
" felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo" +
|
||||
" erat pulvinar nisi, id elementum sapien dolor et diam.", false, 23);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeDecode31() throws Exception {
|
||||
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
|
||||
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
|
||||
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
|
||||
" auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla" +
|
||||
" ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id" +
|
||||
" elementum sapien dolor et diam. Donec ac nunc sodales elit placerat eleifend." +
|
||||
" Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra fringilla, risus" +
|
||||
" justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo diam, lobortis eu" +
|
||||
" tristique ac, p.In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus" +
|
||||
" quis diam cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec" +
|
||||
" laoreet rutrum est, nec convallis mauris condimentum sit amet. Phasellus gravida," +
|
||||
" justo et congue auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec" +
|
||||
" lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar" +
|
||||
" nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit placerat" +
|
||||
" eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra" +
|
||||
" fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo" +
|
||||
" diam, lobortis eu tristique ac, p. In ut magna vel mauris malesuada dictum. Nulla" +
|
||||
" ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum" +
|
||||
" sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet." +
|
||||
" Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit" +
|
||||
" felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo" +
|
||||
" erat pulvinar nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit" +
|
||||
" placerat eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at" +
|
||||
" pharetra fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est." +
|
||||
" Ut justo diam, lobortis eu tristique ac, p.In ut magna vel mauris malesuada" +
|
||||
" dictum. Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id" +
|
||||
" justo rutrum sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum" +
|
||||
" sit amet. Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat," +
|
||||
" eget hendrerit felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet" +
|
||||
" laoreet, justo erat pulvinar nisi, id elementum sapien dolor et diam. Donec ac" +
|
||||
" nunc sodales elit placerat eleifend. Sed ornare luctus ornare. Vestibulum vehicula," +
|
||||
" massa at pharetra fringilla, risus justo faucibus erat, nec porttitor nibh tellus" +
|
||||
" sed est. Ut justo diam, lobortis eu tris. In ut magna vel mauris malesuada dictum." +
|
||||
" Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum" +
|
||||
" sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet." +
|
||||
" Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget" +
|
||||
" hendrerit felis turpis nec lorem.", false, 31);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateModeMessage() {
|
||||
testModeMessage(true, 2, 29, ".X .XXX.. ...X XX.. ..X .XX. .XX.X");
|
||||
testModeMessage(true, 4, 64, "XX XXXXXX .X.. ...X ..XX .X.. XX..");
|
||||
testModeMessage(false, 21, 660, "X.X.. .X.X..X..XX .XXX ..X.. .XXX. .X... ..XXX");
|
||||
testModeMessage(false, 32, 4096, "XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStuffBits() {
|
||||
testStuffBits(5, ".X.X. X.X.X .X.X.",
|
||||
".X.X. X.X.X .X.X.");
|
||||
testStuffBits(5, ".X.X. ..... .X.X",
|
||||
".X.X. ....X ..X.X");
|
||||
testStuffBits(3, "XX. ... ... ..X XXX .X. ..",
|
||||
"XX. ..X ..X ..X ..X .XX XX. .X. ..X");
|
||||
testStuffBits(6, ".X.X.. ...... ..X.XX",
|
||||
".X.X.. .....X. ..X.XX XXXX.");
|
||||
testStuffBits(6, ".X.X.. ...... ...... ..X.X.",
|
||||
".X.X.. .....X .....X ....X. X.XXXX");
|
||||
testStuffBits(6, ".X.X.. XXXXXX ...... ..X.XX",
|
||||
".X.X.. XXXXX. X..... ...X.X XXXXX.");
|
||||
testStuffBits(6,
|
||||
"...... ..XXXX X..XX. .X.... .X.X.X .....X .X.... ...X.X .....X ....XX ..X... ....X. X..XXX X.XX.X",
|
||||
".....X ...XXX XX..XX ..X... ..X.X. X..... X.X... ....X. X..... X....X X..X.. .....X X.X..X XXX.XX .XXXXX");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHighLevelEncode() throws FormatException {
|
||||
testHighLevelEncodeString("A. b.",
|
||||
// 'A' P/S '. ' L/L b D/L '.'
|
||||
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X");
|
||||
testHighLevelEncodeString("Lorem ipsum.",
|
||||
// 'L' L/L 'o' 'r' 'e' 'm' ' ' 'i' 'p' 's' 'u' 'm' D/L '.'
|
||||
".XX.X XXX.. X.... X..XX ..XX. .XXX. ....X .X.X. X...X X.X.. X.XX. .XXX. XXXX. XX.X");
|
||||
testHighLevelEncodeString("Lo. Test 123.",
|
||||
// 'L' L/L 'o' P/S '. ' U/S 'T' 'e' 's' 't' D/L ' ' '1' '2' '3' '.'
|
||||
".XX.X XXX.. X.... ..... ...XX XXX.. X.X.X ..XX. X.X.. X.X.X XXXX. ...X ..XX .X.. .X.X XX.X");
|
||||
testHighLevelEncodeString("Lo...x",
|
||||
// 'L' L/L 'o' D/L '.' '.' '.' U/L L/L 'x'
|
||||
".XX.X XXX.. X.... XXXX. XX.X XX.X XX.X XXX. XXX.. XX..X");
|
||||
testHighLevelEncodeString(". x://abc/.",
|
||||
//P/S '. ' L/L 'x' P/S ':' P/S '/' P/S '/' 'a' 'b' 'c' P/S '/' D/L '.'
|
||||
"..... ...XX XXX.. XX..X ..... X.X.X ..... X.X.. ..... X.X.. ...X. ...XX ..X.. ..... X.X.. XXXX. XX.X");
|
||||
// Uses Binary/Shift rather than Lower/Shift to save two bits.
|
||||
testHighLevelEncodeString("ABCdEFG",
|
||||
//'A' 'B' 'C' B/S =1 'd' 'E' 'F' 'G'
|
||||
"...X. ...XX ..X.. XXXXX ....X .XX..X.. ..XX. ..XXX .X...");
|
||||
|
||||
testHighLevelEncodeString(
|
||||
// Found on an airline boarding pass. Several stretches of Binary shift are
|
||||
// necessary to keep the bitcount so low.
|
||||
"09 UAG ^160MEUCIQC0sYS/HpKxnBELR1uB85R20OoqqwFGa0q2uEi"
|
||||
+ "Ygh6utAIgLl1aBVM4EOTQtMQQYH9M2Z3Dp4qnA/fwWuQ+M8L3V8U=",
|
||||
823);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHighLevelEncodeBinary() throws FormatException {
|
||||
// binary short form single byte
|
||||
testHighLevelEncodeString("N\0N",
|
||||
// 'N' B/S =1 '\0' N
|
||||
".XXXX XXXXX ....X ........ .XXXX"); // Encode "N" in UPPER
|
||||
|
||||
testHighLevelEncodeString("N\0n",
|
||||
// 'N' B/S =2 '\0' 'n'
|
||||
".XXXX XXXXX ...X. ........ .XX.XXX."); // Encode "n" in BINARY
|
||||
|
||||
// binary short form consecutive bytes
|
||||
testHighLevelEncodeString("N\0\u0080 A",
|
||||
// 'N' B/S =2 '\0' \u0080 ' ' 'A'
|
||||
".XXXX XXXXX ...X. ........ X....... ....X ...X.");
|
||||
|
||||
// binary skipping over single character
|
||||
testHighLevelEncodeString("\0a\u00FF\u0080 A",
|
||||
// B/S =4 '\0' 'a' '\3ff' '\200' ' ' 'A'
|
||||
"XXXXX ..X.. ........ .XX....X XXXXXXXX X....... ....X ...X.");
|
||||
|
||||
// getting into binary mode from digit mode
|
||||
testHighLevelEncodeString("1234\0",
|
||||
//D/L '1' '2' '3' '4' U/L B/S =1 \0
|
||||
"XXXX. ..XX .X.. .X.X .XX. XXX. XXXXX ....X ........"
|
||||
);
|
||||
|
||||
// Create a string in which every character requires binary
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i <= 3000; i++) {
|
||||
sb.append((char) (128 + (i % 30)));
|
||||
}
|
||||
// Test the output generated by Binary/Switch, particularly near the
|
||||
// places where the encoding changes: 31, 62, and 2047+31=2078
|
||||
for (int i : new int[] { 1, 2, 3, 10, 29, 30, 31, 32, 33,
|
||||
60, 61, 62, 63, 64, 2076, 2077, 2078, 2079, 2080, 2100 }) {
|
||||
// This is the expected length of a binary string of length "i"
|
||||
int expectedLength = (8 * i) +
|
||||
((i <= 31) ? 10 : (i <= 62) ? 20 : (i <= 2078) ? 21 : 31);
|
||||
// Verify that we are correct about the length.
|
||||
testHighLevelEncodeString(sb.substring(0, i), expectedLength);
|
||||
if (i != 1 && i != 32 && i != 2079) {
|
||||
// The addition of an 'a' at the beginning or end gets merged into the binary code
|
||||
// in those cases where adding another binary character only adds 8 or 9 bits to the result.
|
||||
// So we exclude the border cases i=1,32,2079
|
||||
// A lower case letter at the beginning will be merged into binary mode
|
||||
testHighLevelEncodeString('a' + sb.substring(0, i - 1), expectedLength);
|
||||
// A lower case letter at the end will also be merged into binary mode
|
||||
testHighLevelEncodeString(sb.substring(0, i - 1) + 'a', expectedLength);
|
||||
}
|
||||
// A lower case letter at both ends will enough to latch us into LOWER.
|
||||
testHighLevelEncodeString('a' + sb.substring(0, i) + 'b', expectedLength + 15);
|
||||
}
|
||||
|
||||
sb = new StringBuilder();
|
||||
for (int i = 0; i < 32; i++) {
|
||||
sb.append('§'); // § forces binary encoding
|
||||
}
|
||||
sb.setCharAt(1, 'A');
|
||||
// expect B/S(1) A B/S(30)
|
||||
testHighLevelEncodeString(sb.toString(), 5 + 20 + 31 * 8);
|
||||
|
||||
sb = new StringBuilder();
|
||||
for (int i = 0; i < 31; i++) {
|
||||
sb.append('§');
|
||||
}
|
||||
sb.setCharAt(1, 'A');
|
||||
// expect B/S(31)
|
||||
testHighLevelEncodeString(sb.toString(), 10 + 31 * 8);
|
||||
|
||||
sb = new StringBuilder();
|
||||
for (int i = 0; i < 34; i++) {
|
||||
sb.append('§');
|
||||
}
|
||||
sb.setCharAt(1, 'A');
|
||||
// expect B/S(31) B/S(3)
|
||||
testHighLevelEncodeString(sb.toString(), 20 + 34 * 8);
|
||||
|
||||
sb = new StringBuilder();
|
||||
for (int i = 0; i < 64; i++) {
|
||||
sb.append('§');
|
||||
}
|
||||
sb.setCharAt(30, 'A');
|
||||
// expect B/S(64)
|
||||
testHighLevelEncodeString(sb.toString(), 21 + 64 * 8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHighLevelEncodePairs() throws FormatException {
|
||||
// Typical usage
|
||||
testHighLevelEncodeString("ABC. DEF\r\n",
|
||||
// A B C P/S .<sp> D E F P/S \r\n
|
||||
"...X. ...XX ..X.. ..... ...XX ..X.X ..XX. ..XXX ..... ...X.");
|
||||
|
||||
// We should latch to PUNCT mode, rather than shift. Also check all pairs
|
||||
testHighLevelEncodeString("A. : , \r\n",
|
||||
// 'A' M/L P/L ". " ": " ", " "\r\n"
|
||||
"...X. XXX.X XXXX. ...XX ..X.X ..X.. ...X.");
|
||||
|
||||
// Latch to DIGIT rather than shift to PUNCT
|
||||
testHighLevelEncodeString("A. 1234",
|
||||
// 'A' D/L '.' ' ' '1' '2' '3' '4'
|
||||
"...X. XXXX. XX.X ...X ..XX .X.. .X.X .X X.");
|
||||
// Don't bother leaving Binary Shift.
|
||||
testHighLevelEncodeString("A\200. \200",
|
||||
// 'A' B/S =2 \200 "." " " \200
|
||||
"...X. XXXXX ..X.. X....... ..X.XXX. ..X..... X.......");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testUserSpecifiedLayers() {
|
||||
doTestUserSpecifiedLayers(33);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testUserSpecifiedLayers2() {
|
||||
doTestUserSpecifiedLayers(-1);
|
||||
}
|
||||
|
||||
private void doTestUserSpecifiedLayers(int userSpecifiedLayers) {
|
||||
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
AztecCode aztec = Encoder.encode(alphabet, 25, -2);
|
||||
assertEquals(2, aztec.getLayers());
|
||||
assertTrue(aztec.isCompact());
|
||||
|
||||
aztec = Encoder.encode(alphabet, 25, 32);
|
||||
assertEquals(32, aztec.getLayers());
|
||||
assertFalse(aztec.isCompact());
|
||||
|
||||
Encoder.encode(alphabet, 25, userSpecifiedLayers);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testBorderCompact4CaseFailed() {
|
||||
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
|
||||
// be error correction
|
||||
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
// encodes as 26 * 5 * 4 = 520 bits of data
|
||||
String alphabet4 = alphabet + alphabet + alphabet + alphabet;
|
||||
Encoder.encode(alphabet4, 0, -4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBorderCompact4Case() {
|
||||
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
|
||||
// be error correction
|
||||
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
// encodes as 26 * 5 * 4 = 520 bits of data
|
||||
String alphabet4 = alphabet + alphabet + alphabet + alphabet;
|
||||
|
||||
// If we just try to encode it normally, it will go to a non-compact 4 layer
|
||||
AztecCode aztecCode = Encoder.encode(alphabet4, 0, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||
assertFalse(aztecCode.isCompact());
|
||||
assertEquals(4, aztecCode.getLayers());
|
||||
|
||||
// But shortening the string to 100 bytes (500 bits of data), compact works fine, even if we
|
||||
// include more error checking.
|
||||
aztecCode = Encoder.encode(alphabet4.substring(0, 100), 10, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||
assertTrue(aztecCode.isCompact());
|
||||
assertEquals(4, aztecCode.getLayers());
|
||||
}
|
||||
|
||||
// Helper routines
|
||||
|
||||
private static void testEncode(String data, boolean compact, int layers, String expected) {
|
||||
AztecCode aztec = Encoder.encode(data, 33, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
|
||||
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
|
||||
BitMatrix matrix = aztec.getMatrix();
|
||||
assertEquals("encode() failed", expected, matrix.toString());
|
||||
}
|
||||
|
||||
private static void testEncodeDecode(String data, boolean compact, int layers) throws Exception {
|
||||
AztecCode aztec = Encoder.encode(data, 25, Encoder.DEFAULT_AZTEC_LAYERS);
|
||||
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
|
||||
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
|
||||
BitMatrix matrix = aztec.getMatrix();
|
||||
AztecDetectorRXingResult r =
|
||||
new AztecDetectorRXingResult(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
|
||||
DecoderRXingResult res = new Decoder().decode(r);
|
||||
assertEquals(data, res.getText());
|
||||
// Check error correction by introducing a few minor errors
|
||||
Random random = getPseudoRandom();
|
||||
matrix.flip(random.nextInt(matrix.getWidth()), random.nextInt(2));
|
||||
matrix.flip(random.nextInt(matrix.getWidth()), matrix.getHeight() - 2 + random.nextInt(2));
|
||||
matrix.flip(random.nextInt(2), random.nextInt(matrix.getHeight()));
|
||||
matrix.flip(matrix.getWidth() - 2 + random.nextInt(2), random.nextInt(matrix.getHeight()));
|
||||
r = new AztecDetectorRXingResult(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
|
||||
res = new Decoder().decode(r);
|
||||
assertEquals(data, res.getText());
|
||||
}
|
||||
|
||||
private static void testWriter(String data,
|
||||
Charset charset,
|
||||
int eccPercent,
|
||||
boolean compact,
|
||||
int layers) throws FormatException {
|
||||
// Perform an encode-decode round-trip because it can be lossy.
|
||||
Map<EncodeHintType,Object> hints = new EnumMap<>(EncodeHintType.class);
|
||||
if (null != charset) {
|
||||
hints.put(EncodeHintType.CHARACTER_SET, charset.name());
|
||||
}
|
||||
hints.put(EncodeHintType.ERROR_CORRECTION, eccPercent);
|
||||
AztecWriter writer = new AztecWriter();
|
||||
BitMatrix matrix = writer.encode(data, BarcodeFormat.AZTEC, 0, 0, hints);
|
||||
AztecCode aztec = Encoder.encode(data, eccPercent,
|
||||
Encoder.DEFAULT_AZTEC_LAYERS, charset);
|
||||
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
|
||||
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
|
||||
BitMatrix matrix2 = aztec.getMatrix();
|
||||
assertEquals(matrix, matrix2);
|
||||
AztecDetectorRXingResult r =
|
||||
new AztecDetectorRXingResult(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
|
||||
DecoderRXingResult res = new Decoder().decode(r);
|
||||
assertEquals(data, res.getText());
|
||||
// Check error correction by introducing up to eccPercent/2 errors
|
||||
int ecWords = aztec.getCodeWords() * eccPercent / 100 / 2;
|
||||
Random random = getPseudoRandom();
|
||||
for (int i = 0; i < ecWords; i++) {
|
||||
// don't touch the core
|
||||
int x = random.nextBoolean() ?
|
||||
random.nextInt(aztec.getLayers() * 2)
|
||||
: matrix.getWidth() - 1 - random.nextInt(aztec.getLayers() * 2);
|
||||
int y = random.nextBoolean() ?
|
||||
random.nextInt(aztec.getLayers() * 2)
|
||||
: matrix.getHeight() - 1 - random.nextInt(aztec.getLayers() * 2);
|
||||
matrix.flip(x, y);
|
||||
}
|
||||
r = new AztecDetectorRXingResult(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
|
||||
res = new Decoder().decode(r);
|
||||
assertEquals(data, res.getText());
|
||||
}
|
||||
|
||||
private static Random getPseudoRandom() {
|
||||
return new Random(0xDEADBEEF);
|
||||
}
|
||||
|
||||
private static void testModeMessage(boolean compact, int layers, int words, String expected) {
|
||||
BitArray in = Encoder.generateModeMessage(compact, layers, words);
|
||||
assertEquals("generateModeMessage() failed", stripSpace(expected), stripSpace(in.toString()));
|
||||
}
|
||||
|
||||
private static void testStuffBits(int wordSize, String bits, String expected) {
|
||||
BitArray in = toBitArray(bits);
|
||||
BitArray stuffed = Encoder.stuffBits(in, wordSize);
|
||||
assertEquals("stuffBits() failed for input string: " + bits,
|
||||
stripSpace(expected), stripSpace(stuffed.toString()));
|
||||
}
|
||||
|
||||
public static BitArray toBitArray(CharSequence bits) {
|
||||
BitArray in = new BitArray();
|
||||
char[] str = DOTX.matcher(bits).replaceAll("").toCharArray();
|
||||
for (char aStr : str) {
|
||||
in.appendBit(aStr == 'X');
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
public static boolean[] toBooleanArray(BitArray bitArray) {
|
||||
boolean[] result = new boolean[bitArray.getSize()];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = bitArray.get(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void testHighLevelEncodeString(String s, String expectedBits) throws FormatException {
|
||||
BitArray bits = new HighLevelEncoder(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
|
||||
String receivedBits = stripSpace(bits.toString());
|
||||
assertEquals("highLevelEncode() failed for input string: " + s, stripSpace(expectedBits), receivedBits);
|
||||
assertEquals(s, Decoder.highLevelDecode(toBooleanArray(bits)));
|
||||
}
|
||||
|
||||
private static void testHighLevelEncodeString(String s, int expectedReceivedBits) throws FormatException {
|
||||
BitArray bits = new HighLevelEncoder(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
|
||||
int receivedBitCount = stripSpace(bits.toString()).length();
|
||||
assertEquals("highLevelEncode() failed for input string: " + s,
|
||||
expectedReceivedBits, receivedBitCount);
|
||||
assertEquals(s, Decoder.highLevelDecode(toBooleanArray(bits)));
|
||||
}
|
||||
|
||||
public static String stripSpace(String s) {
|
||||
return SPACES.matcher(s).replaceAll("");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user