Add more hints for Aztec encoding

git-svn-id: https://zxing.googlecode.com/svn/trunk@2587 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen@gmail.com 2013-03-06 13:16:23 +00:00
parent cd8985336d
commit 883751b8ba
3 changed files with 86 additions and 7 deletions

View file

@ -27,6 +27,8 @@ public enum EncodeHintType {
* Specifies what degree of error correction to use, for example in QR Codes.
* Type depends on the encoder. For example for QR codes it's type
* {@link com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ErrorCorrectionLevel}.
* For Aztec it is of type {@link Integer}, representing the minimal percentage of error correction words.
* Note: an Aztec symbol should have a minimum of 25% EC words.
*/
ERROR_CORRECTION,

View file

@ -26,17 +26,29 @@ import com.google.zxing.common.BitMatrix;
public final class AztecWriter implements Writer {
private static final Charset LATIN_1 = Charset.forName("ISO-8859-1");
private static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");
@Override
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height) {
AztecCode aztec = Encoder.encode(contents.getBytes(LATIN_1), 30);
return aztec.getMatrix();
return encode(contents, format, DEFAULT_CHARSET, Encoder.DEFAULT_EC_PERCENT);
}
@Override
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Map<EncodeHintType,?> hints) {
return encode(contents, format, width, height);
String charset = (String) hints.get(EncodeHintType.CHARACTER_SET);
Number eccPercent = (Number) hints.get(EncodeHintType.ERROR_CORRECTION);
return encode(contents,
format,
charset == null ? DEFAULT_CHARSET : Charset.forName(charset),
eccPercent == null ? Encoder.DEFAULT_EC_PERCENT : eccPercent.intValue());
}
private static BitMatrix encode(String contents, BarcodeFormat format, Charset charset, int eccPercent) {
if (format != BarcodeFormat.AZTEC) {
throw new IllegalArgumentException("Can only encode QR_AZTECCODE, but got " + format);
}
AztecCode aztec = Encoder.encode(contents.getBytes(charset), eccPercent);
return aztec.getMatrix();
}
}

View file

@ -18,12 +18,17 @@ package com.google.zxing.aztec.encoder;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.util.EnumMap;
import java.util.Map;
import java.util.Random;
import java.util.regex.Pattern;
import com.google.zxing.FormatException;
import org.junit.Assert;
import org.junit.Test;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.ResultPoint;
import com.google.zxing.aztec.AztecDetectorResult;
import com.google.zxing.aztec.decoder.Decoder;
@ -120,6 +125,23 @@ public final class EncoderTest extends Assert {
"X X X X X X X X X X X X X \n");
}
@Test
public void testAztecWriter() throws Exception {
testWriter("\u20AC 1 sample data.", "ISO-8859-1", 25, true, 2);
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);
// 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.getBytes(LATIN_1), Encoder.DEFAULT_EC_PERCENT);
BitMatrix expectedMatrix = aztec.getMatrix();
assertEquals(matrix, expectedMatrix);
}
// synthetic tests (encode-decode round-trip)
@Test
@ -277,7 +299,8 @@ public final class EncoderTest extends Assert {
testHighLevelEncodeString("\0a\u00FF\u0080 A",
"XXXXX ..X.. ........ .XX....X XXXXXXXX X....... ....X ...X.");
// binary long form optimization into 2 short forms (saves 1 bit)
testHighLevelEncodeString("\0\0\0\0 \0\0\0\0 \0\0\0\0 \0\0\0\0 \0\0\0\0 \0\0\0\0 \u0082\u0084\u0088\0 \0\0\0\0 \0\0\0\0 ",
testHighLevelEncodeString(
"\0\0\0\0 \0\0\0\0 \0\0\0\0 \0\0\0\0 \0\0\0\0 \0\0\0\0 \u0082\u0084\u0088\0 \0\0\0\0 \0\0\0\0 ",
"XXXXX XXXXX ........ ........ ........ ........ ..X....." +
" ........ ........ ........ ........ ..X....." +
" ........ ........ ........ ........ ..X....." +
@ -288,7 +311,9 @@ public final class EncoderTest extends Assert {
" ........ ........ ........ ........ ..X....." +
" ........ ........ ........ ........ ..X.....");
// binary long form
testHighLevelEncodeString("\0\0\0\0 \0\0\1\0 \0\0\2\0 \0\0\3\0 \0\0\4\0 \0\0\5\0 \0\0\6\0 \0\0\7\0 \0\0\u0008\0 \0\0\u0009\0 \0\0\u00F0\0 \0\0\u00F1\0 \0\0\u00F2\0A",
testHighLevelEncodeString(
"\0\0\0\0 \0\0\1\0 \0\0\2\0 \0\0\3\0 \0\0\4\0 \0\0\5\0 \0\0\6\0 \0\0\7\0 \0\0\u0008" +
"\0 \0\0\u0009\0 \0\0\u00F0\0 \0\0\u00F1\0 \0\0\u00F2\0A",
"XXXXX ..... .....X...X. ........ ........ ........ ........ ..X....." +
" ........ ........ .......X ........ ..X....." +
" ........ ........ ......X. ........ ..X....." +
@ -334,6 +359,46 @@ public final class EncoderTest extends Assert {
assertEquals(data, res.getText());
}
private static void testWriter(String data,
String charset,
int eccPercent,
boolean compact,
int layers) throws FormatException {
// 1. Perform an encode-decode round-trip because it can be lossy.
// 2. Aztec Decoder currently always decodes the data with a LATIN-1 charset:
String expectedData = new String(data.getBytes(Charset.forName(charset)), LATIN_1);
Map<EncodeHintType,Object> hints = new EnumMap<EncodeHintType,Object>(EncodeHintType.class);
hints.put(EncodeHintType.CHARACTER_SET, charset);
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.getBytes(Charset.forName(charset)), eccPercent);
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
BitMatrix matrix2 = aztec.getMatrix();
assertEquals(matrix, matrix2);
AztecDetectorResult r =
new AztecDetectorResult(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
DecoderResult res = new Decoder().decode(r);
assertEquals(expectedData, res.getText());
// Check error correction by introducing up to eccPercent errors
int ecWords = aztec.getCodeWords() * eccPercent / 100;
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 AztecDetectorResult(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
res = new Decoder().decode(r);
assertEquals(expectedData, res.getText());
}
static Random getPseudoRandom() {
return new SecureRandom(new byte[] {(byte) 0xDE, (byte) 0xAD, (byte) 0xBE, (byte) 0xEF});
}