From 883751b8bad2153578a657a69ad982c6f53ae517 Mon Sep 17 00:00:00 2001 From: "srowen@gmail.com" Date: Wed, 6 Mar 2013 13:16:23 +0000 Subject: [PATCH] Add more hints for Aztec encoding git-svn-id: https://zxing.googlecode.com/svn/trunk@2587 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- core/src/com/google/zxing/EncodeHintType.java | 2 + .../zxing/aztec/encoder/AztecWriter.java | 22 ++++-- .../zxing/aztec/encoder/EncoderTest.java | 69 ++++++++++++++++++- 3 files changed, 86 insertions(+), 7 deletions(-) diff --git a/core/src/com/google/zxing/EncodeHintType.java b/core/src/com/google/zxing/EncodeHintType.java index 641e502a2..340b59485 100644 --- a/core/src/com/google/zxing/EncodeHintType.java +++ b/core/src/com/google/zxing/EncodeHintType.java @@ -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, diff --git a/core/src/com/google/zxing/aztec/encoder/AztecWriter.java b/core/src/com/google/zxing/aztec/encoder/AztecWriter.java index 669d1236b..edc92ccb1 100644 --- a/core/src/com/google/zxing/aztec/encoder/AztecWriter.java +++ b/core/src/com/google/zxing/aztec/encoder/AztecWriter.java @@ -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 hints) { - return encode(contents, format, width, height); + public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Map hints) { + 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(); } } diff --git a/core/test/src/com/google/zxing/aztec/encoder/EncoderTest.java b/core/test/src/com/google/zxing/aztec/encoder/EncoderTest.java index 7f6078d11..a4e5dc6c1 100644 --- a/core/test/src/com/google/zxing/aztec/encoder/EncoderTest.java +++ b/core/test/src/com/google/zxing/aztec/encoder/EncoderTest.java @@ -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 hints = new EnumMap(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}); }