More changes in the direction of supporting ECI in the encoder
authorsrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Sat, 31 Jan 2009 20:17:43 +0000 (20:17 +0000)
committersrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Sat, 31 Jan 2009 20:17:43 +0000 (20:17 +0000)
git-svn-id: http://zxing.googlecode.com/svn/trunk@837 59b500cc-1b3d-0410-9834-0bbf25fbcc57

core/src/com/google/zxing/common/CharacterSetECI.java
core/src/com/google/zxing/common/ECI.java
core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java
core/src/com/google/zxing/qrcode/encoder/Encoder.java
core/test/src/com/google/zxing/qrcode/encoder/EncoderTestCase.java

index 91f2ec4..a0d1f0f 100644 (file)
@@ -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
index 8a6f446..dbb9556 100644 (file)
@@ -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;
   }
 
 }
index 76156dd..8ce3ee3 100644 (file)
@@ -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 {
index cbda61e..c9d64a9 100644 (file)
@@ -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
+  }
+
 }
index 37c998d..86e6200 100644 (file)
@@ -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());
     }
   }