From 70367e61773d80a4654f37bbfcf6c0104e97ebaf Mon Sep 17 00:00:00 2001 From: srowen Date: Sat, 31 Jan 2009 20:17:43 +0000 Subject: [PATCH] More changes in the direction of supporting ECI in the encoder git-svn-id: http://zxing.googlecode.com/svn/trunk@837 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- .../google/zxing/common/CharacterSetECI.java | 51 +++++++++++++++---- core/src/com/google/zxing/common/ECI.java | 7 ++- .../decoder/DecodedBitStreamParser.java | 7 ++- .../google/zxing/qrcode/encoder/Encoder.java | 26 ++++++++-- .../zxing/qrcode/encoder/EncoderTestCase.java | 16 +++--- 5 files changed, 81 insertions(+), 26 deletions(-) diff --git a/core/src/com/google/zxing/common/CharacterSetECI.java b/core/src/com/google/zxing/common/CharacterSetECI.java index 91f2ec42..a0d1f0f7 100644 --- a/core/src/com/google/zxing/common/CharacterSetECI.java +++ b/core/src/com/google/zxing/common/CharacterSetECI.java @@ -26,14 +26,17 @@ import java.util.Hashtable; */ public final class CharacterSetECI extends ECI { - private static final Hashtable VALUE_TO_ECI; - static { + private static Hashtable VALUE_TO_ECI; + private static Hashtable NAME_TO_ECI; + + private static void initialize() { VALUE_TO_ECI = new Hashtable(29); + NAME_TO_ECI = new Hashtable(29); // TODO figure out if these values are even right! addCharacterSet(0, "Cp437"); - addCharacterSet(1, "ISO8859_1"); + addCharacterSet(1, new String[] {"ISO8859_1", "ISO-8859-1"}); addCharacterSet(2, "Cp437"); - addCharacterSet(3, "ISO8859_1"); + addCharacterSet(3, new String[] {"ISO8859_1", "ISO-8859-1"}); addCharacterSet(4, "ISO8859_2"); addCharacterSet(5, "ISO8859_3"); addCharacterSet(6, "ISO8859_4"); @@ -48,7 +51,7 @@ public final class CharacterSetECI extends ECI { addCharacterSet(16, "ISO8859_14"); addCharacterSet(17, "ISO8859_15"); addCharacterSet(18, "ISO8859_16"); - addCharacterSet(20, "SJIS"); + addCharacterSet(20, new String[] {"SJIS", "Shift_JIS"}); } private final String encodingName; @@ -63,15 +66,43 @@ public final class CharacterSetECI extends ECI { } private static void addCharacterSet(int value, String encodingName) { - VALUE_TO_ECI.put(new Integer(value), new CharacterSetECI(value, encodingName)); + CharacterSetECI eci = new CharacterSetECI(value, encodingName); + VALUE_TO_ECI.put(new Integer(value), eci); + NAME_TO_ECI.put(encodingName, eci); + } + + private static void addCharacterSet(int value, String[] encodingNames) { + CharacterSetECI eci = new CharacterSetECI(value, encodingNames[0]); + VALUE_TO_ECI.put(new Integer(value), eci); + for (int i = 0; i < encodingNames.length; i++) { + NAME_TO_ECI.put(encodingNames[i], eci); + } } + /** + * @param value character set ECI value + * @return {@link CharacterSetECI} representing ECI of given value, or null if it is legal but unsupported + * @throws IllegalArgumentException if ECI value is invalid + */ public static CharacterSetECI getCharacterSetECIByValue(int value) { - CharacterSetECI eci = (CharacterSetECI) VALUE_TO_ECI.get(new Integer(value)); - if (eci == null) { - throw new IllegalArgumentException("Unsupported value: " + value); + if (VALUE_TO_ECI == null) { + initialize(); + } + if (value < 0 || value >= 900) { + throw new IllegalArgumentException("Bad ECI value: " + value); + } + return (CharacterSetECI) VALUE_TO_ECI.get(new Integer(value)); + } + + /** + * @param name character set ECI encoding name + * @return {@link CharacterSetECI} representing ECI for character encoding, or null if it is legal but unsupported + */ + public static CharacterSetECI getCharacterSetECIByName(String name) { + if (NAME_TO_ECI == null) { + initialize(); } - return eci; + return (CharacterSetECI) NAME_TO_ECI.get(name); } } \ No newline at end of file diff --git a/core/src/com/google/zxing/common/ECI.java b/core/src/com/google/zxing/common/ECI.java index 8a6f446b..dbb9556b 100644 --- a/core/src/com/google/zxing/common/ECI.java +++ b/core/src/com/google/zxing/common/ECI.java @@ -34,6 +34,11 @@ public abstract class ECI { return value; } + /** + * @param value ECI value + * @return {@link ECI} representing ECI of given value, or null if it is legal but unsupported + * @throws IllegalArgumentException if ECI value is invalid + */ public static ECI getECIByValue(int value) { if (value < 0 || value > 999999) { throw new IllegalArgumentException("Bad ECI value: " + value); @@ -41,7 +46,7 @@ public abstract class ECI { if (value < 900) { // Character set ECIs use 000000 - 000899 return CharacterSetECI.getCharacterSetECIByValue(value); } - throw new IllegalArgumentException("Unsupported ECI value: " + value); + return null; } } diff --git a/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java b/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java index 76156dd0..8ce3ee3b 100644 --- a/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java +++ b/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java @@ -86,10 +86,9 @@ final class DecodedBitStreamParser { bits.readBits(16); } else if (mode.equals(Mode.ECI)) { // Count doesn't apply to ECI - try { - int value = parseECIValue(bits); - currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value); - } catch (IllegalArgumentException iae) { + int value = parseECIValue(bits); + currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value); + if (currentCharacterSetECI == null) { throw ReaderException.getInstance(); } } else { diff --git a/core/src/com/google/zxing/qrcode/encoder/Encoder.java b/core/src/com/google/zxing/qrcode/encoder/Encoder.java index cbda61e1..c9d64a9a 100644 --- a/core/src/com/google/zxing/qrcode/encoder/Encoder.java +++ b/core/src/com/google/zxing/qrcode/encoder/Encoder.java @@ -20,6 +20,7 @@ import com.google.zxing.WriterException; import com.google.zxing.EncodeHintType; import com.google.zxing.common.ByteArray; import com.google.zxing.common.ByteMatrix; +import com.google.zxing.common.CharacterSetECI; import com.google.zxing.common.reedsolomon.GF256; import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; @@ -46,6 +47,8 @@ public final class Encoder { 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f }; + static final String DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1"; + private Encoder() { } @@ -101,7 +104,7 @@ public final class Encoder { String characterEncoding = hints == null ? null : (String) hints.get(EncodeHintType.CHARACTER_SET); if (characterEncoding == null) { - characterEncoding = "ISO-8859-1"; + characterEncoding = DEFAULT_BYTE_MODE_ENCODING; } // Step 1: Choose the mode (encoding). @@ -116,8 +119,18 @@ public final class Encoder { // Step 4: Build another bit vector that contains header and data. BitVector headerAndDataBits = new BitVector(); - appendModeInfo(qrCode.getMode(), headerAndDataBits); - appendLengthInfo(content.length(), qrCode.getVersion(), qrCode.getMode(), headerAndDataBits); + + // Step 4.5: Append ECI message if applicable + /* + if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.equals(characterEncoding)) { + CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(characterEncoding); + if (eci != null) { + appendECI(eci, headerAndDataBits); + } + } + */ + appendModeInfo(mode, headerAndDataBits); + appendLengthInfo(content.length(), qrCode.getVersion(), mode, headerAndDataBits); headerAndDataBits.appendBitVector(dataBits); // Step 5: Terminate the bits properly. @@ -247,6 +260,8 @@ public final class Encoder { throw new WriterException("data bits cannot fit in the QR Code" + bits.size() + " > " + capacity); } // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details. + // TODO srowen says we can remove this for loop, since the 4 terminator bits are optional if the last byte + // has less than 4 bits left. So it amounts to padding the last byte with zeroes either way. for (int i = 0; i < 4 && bits.size() < capacity; ++i) { bits.appendBit(0); } @@ -532,4 +547,9 @@ public final class Encoder { } } + static void appendECI(CharacterSetECI eci, BitVector bits) { + bits.appendBits(Mode.ECI.getBits(), 4); + bits.appendBits(eci.getValue(), 8); // This is correct for values up to 127, which is all we need now + } + } diff --git a/core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java b/core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java index 37c998d8..86e6200d 100644 --- a/core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java +++ b/core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java @@ -171,18 +171,18 @@ public final class EncoderTestCase extends TestCase { // Should use appendNumericBytes. // 1 = 01 = 0001 in 4 bits. BitVector bits = new BitVector(); - Encoder.appendBytes("1", Mode.NUMERIC, bits); + Encoder.appendBytes("1", Mode.NUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); assertEquals("0001" , bits.toString()); } { // Should use appendAlphanumericBytes. // A = 10 = 0xa = 001010 in 6 bits BitVector bits = new BitVector(); - Encoder.appendBytes("A", Mode.ALPHANUMERIC, bits); + Encoder.appendBytes("A", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); assertEquals("001010" , bits.toString()); // Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC. try { - Encoder.appendBytes("a", Mode.ALPHANUMERIC, bits); + Encoder.appendBytes("a", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); } catch (WriterException we) { // good } @@ -191,16 +191,16 @@ public final class EncoderTestCase extends TestCase { // Should use append8BitBytes. // 0x61, 0x62, 0x63 BitVector bits = new BitVector(); - Encoder.appendBytes("abc", Mode.BYTE, bits); + Encoder.appendBytes("abc", Mode.BYTE, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); assertEquals("011000010110001001100011", bits.toString()); // Anything can be encoded in QRCode.MODE_8BIT_BYTE. - Encoder.appendBytes("\0", Mode.BYTE, bits); + Encoder.appendBytes("\0", Mode.BYTE, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); } { // Should use appendKanjiBytes. // 0x93, 0x5f BitVector bits = new BitVector(); - Encoder.appendBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), Mode.KANJI, bits); + Encoder.appendBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), Mode.KANJI, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); assertEquals("0110110011111", bits.toString()); } } @@ -420,13 +420,13 @@ public final class EncoderTestCase extends TestCase { { // 0x61, 0x62, 0x63 BitVector bits = new BitVector(); - Encoder.append8BitBytes("abc", bits); + Encoder.append8BitBytes("abc", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); assertEquals("01100001" + "01100010" + "01100011", bits.toString()); } { // Empty. BitVector bits = new BitVector(); - Encoder.append8BitBytes("", bits); + Encoder.append8BitBytes("", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); assertEquals("", bits.toString()); } } -- 2.20.1