mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
More changes in the direction of supporting ECI in the encoder
git-svn-id: https://zxing.googlecode.com/svn/trunk@837 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
807c1646b9
commit
db61519508
|
@ -26,14 +26,17 @@ import java.util.Hashtable;
|
||||||
*/
|
*/
|
||||||
public final class CharacterSetECI extends ECI {
|
public final class CharacterSetECI extends ECI {
|
||||||
|
|
||||||
private static final Hashtable VALUE_TO_ECI;
|
private static Hashtable VALUE_TO_ECI;
|
||||||
static {
|
private static Hashtable NAME_TO_ECI;
|
||||||
|
|
||||||
|
private static void initialize() {
|
||||||
VALUE_TO_ECI = new Hashtable(29);
|
VALUE_TO_ECI = new Hashtable(29);
|
||||||
|
NAME_TO_ECI = new Hashtable(29);
|
||||||
// TODO figure out if these values are even right!
|
// TODO figure out if these values are even right!
|
||||||
addCharacterSet(0, "Cp437");
|
addCharacterSet(0, "Cp437");
|
||||||
addCharacterSet(1, "ISO8859_1");
|
addCharacterSet(1, new String[] {"ISO8859_1", "ISO-8859-1"});
|
||||||
addCharacterSet(2, "Cp437");
|
addCharacterSet(2, "Cp437");
|
||||||
addCharacterSet(3, "ISO8859_1");
|
addCharacterSet(3, new String[] {"ISO8859_1", "ISO-8859-1"});
|
||||||
addCharacterSet(4, "ISO8859_2");
|
addCharacterSet(4, "ISO8859_2");
|
||||||
addCharacterSet(5, "ISO8859_3");
|
addCharacterSet(5, "ISO8859_3");
|
||||||
addCharacterSet(6, "ISO8859_4");
|
addCharacterSet(6, "ISO8859_4");
|
||||||
|
@ -48,7 +51,7 @@ public final class CharacterSetECI extends ECI {
|
||||||
addCharacterSet(16, "ISO8859_14");
|
addCharacterSet(16, "ISO8859_14");
|
||||||
addCharacterSet(17, "ISO8859_15");
|
addCharacterSet(17, "ISO8859_15");
|
||||||
addCharacterSet(18, "ISO8859_16");
|
addCharacterSet(18, "ISO8859_16");
|
||||||
addCharacterSet(20, "SJIS");
|
addCharacterSet(20, new String[] {"SJIS", "Shift_JIS"});
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String encodingName;
|
private final String encodingName;
|
||||||
|
@ -63,15 +66,43 @@ public final class CharacterSetECI extends ECI {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addCharacterSet(int value, String encodingName) {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CharacterSetECI getCharacterSetECIByValue(int value) {
|
private static void addCharacterSet(int value, String[] encodingNames) {
|
||||||
CharacterSetECI eci = (CharacterSetECI) VALUE_TO_ECI.get(new Integer(value));
|
CharacterSetECI eci = new CharacterSetECI(value, encodingNames[0]);
|
||||||
if (eci == null) {
|
VALUE_TO_ECI.put(new Integer(value), eci);
|
||||||
throw new IllegalArgumentException("Unsupported value: " + value);
|
for (int i = 0; i < encodingNames.length; i++) {
|
||||||
|
NAME_TO_ECI.put(encodingNames[i], eci);
|
||||||
}
|
}
|
||||||
return 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) {
|
||||||
|
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 (CharacterSetECI) NAME_TO_ECI.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -34,6 +34,11 @@ public abstract class ECI {
|
||||||
return value;
|
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) {
|
public static ECI getECIByValue(int value) {
|
||||||
if (value < 0 || value > 999999) {
|
if (value < 0 || value > 999999) {
|
||||||
throw new IllegalArgumentException("Bad ECI value: " + value);
|
throw new IllegalArgumentException("Bad ECI value: " + value);
|
||||||
|
@ -41,7 +46,7 @@ public abstract class ECI {
|
||||||
if (value < 900) { // Character set ECIs use 000000 - 000899
|
if (value < 900) { // Character set ECIs use 000000 - 000899
|
||||||
return CharacterSetECI.getCharacterSetECIByValue(value);
|
return CharacterSetECI.getCharacterSetECIByValue(value);
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Unsupported ECI value: " + value);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,10 +86,9 @@ final class DecodedBitStreamParser {
|
||||||
bits.readBits(16);
|
bits.readBits(16);
|
||||||
} else if (mode.equals(Mode.ECI)) {
|
} else if (mode.equals(Mode.ECI)) {
|
||||||
// Count doesn't apply to ECI
|
// Count doesn't apply to ECI
|
||||||
try {
|
int value = parseECIValue(bits);
|
||||||
int value = parseECIValue(bits);
|
currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value);
|
||||||
currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value);
|
if (currentCharacterSetECI == null) {
|
||||||
} catch (IllegalArgumentException iae) {
|
|
||||||
throw ReaderException.getInstance();
|
throw ReaderException.getInstance();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import com.google.zxing.WriterException;
|
||||||
import com.google.zxing.EncodeHintType;
|
import com.google.zxing.EncodeHintType;
|
||||||
import com.google.zxing.common.ByteArray;
|
import com.google.zxing.common.ByteArray;
|
||||||
import com.google.zxing.common.ByteMatrix;
|
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.GF256;
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonEncoder;
|
import com.google.zxing.common.reedsolomon.ReedSolomonEncoder;
|
||||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
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
|
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() {
|
private Encoder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +104,7 @@ public final class Encoder {
|
||||||
|
|
||||||
String characterEncoding = hints == null ? null : (String) hints.get(EncodeHintType.CHARACTER_SET);
|
String characterEncoding = hints == null ? null : (String) hints.get(EncodeHintType.CHARACTER_SET);
|
||||||
if (characterEncoding == null) {
|
if (characterEncoding == null) {
|
||||||
characterEncoding = "ISO-8859-1";
|
characterEncoding = DEFAULT_BYTE_MODE_ENCODING;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 1: Choose the 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.
|
// Step 4: Build another bit vector that contains header and data.
|
||||||
BitVector headerAndDataBits = new BitVector();
|
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);
|
headerAndDataBits.appendBitVector(dataBits);
|
||||||
|
|
||||||
// Step 5: Terminate the bits properly.
|
// 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);
|
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.
|
// 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) {
|
for (int i = 0; i < 4 && bits.size() < capacity; ++i) {
|
||||||
bits.appendBit(0);
|
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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,18 +171,18 @@ public final class EncoderTestCase extends TestCase {
|
||||||
// Should use appendNumericBytes.
|
// Should use appendNumericBytes.
|
||||||
// 1 = 01 = 0001 in 4 bits.
|
// 1 = 01 = 0001 in 4 bits.
|
||||||
BitVector bits = new BitVector();
|
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());
|
assertEquals("0001" , bits.toString());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// Should use appendAlphanumericBytes.
|
// Should use appendAlphanumericBytes.
|
||||||
// A = 10 = 0xa = 001010 in 6 bits
|
// A = 10 = 0xa = 001010 in 6 bits
|
||||||
BitVector bits = new BitVector();
|
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());
|
assertEquals("001010" , bits.toString());
|
||||||
// Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
|
// Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
|
||||||
try {
|
try {
|
||||||
Encoder.appendBytes("a", Mode.ALPHANUMERIC, bits);
|
Encoder.appendBytes("a", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
|
||||||
} catch (WriterException we) {
|
} catch (WriterException we) {
|
||||||
// good
|
// good
|
||||||
}
|
}
|
||||||
|
@ -191,16 +191,16 @@ public final class EncoderTestCase extends TestCase {
|
||||||
// Should use append8BitBytes.
|
// Should use append8BitBytes.
|
||||||
// 0x61, 0x62, 0x63
|
// 0x61, 0x62, 0x63
|
||||||
BitVector bits = new BitVector();
|
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());
|
assertEquals("011000010110001001100011", bits.toString());
|
||||||
// Anything can be encoded in QRCode.MODE_8BIT_BYTE.
|
// 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.
|
// Should use appendKanjiBytes.
|
||||||
// 0x93, 0x5f
|
// 0x93, 0x5f
|
||||||
BitVector bits = new BitVector();
|
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());
|
assertEquals("0110110011111", bits.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,13 +420,13 @@ public final class EncoderTestCase extends TestCase {
|
||||||
{
|
{
|
||||||
// 0x61, 0x62, 0x63
|
// 0x61, 0x62, 0x63
|
||||||
BitVector bits = new BitVector();
|
BitVector bits = new BitVector();
|
||||||
Encoder.append8BitBytes("abc", bits);
|
Encoder.append8BitBytes("abc", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
|
||||||
assertEquals("01100001" + "01100010" + "01100011", bits.toString());
|
assertEquals("01100001" + "01100010" + "01100011", bits.toString());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// Empty.
|
// Empty.
|
||||||
BitVector bits = new BitVector();
|
BitVector bits = new BitVector();
|
||||||
Encoder.append8BitBytes("", bits);
|
Encoder.append8BitBytes("", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
|
||||||
assertEquals("", bits.toString());
|
assertEquals("", bits.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue