mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Added basic support for caller-specified character encoding
git-svn-id: https://zxing.googlecode.com/svn/trunk@836 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
89176baf0c
commit
807c1646b9
|
@ -28,6 +28,11 @@ public final class EncodeHintType {
|
||||||
*/
|
*/
|
||||||
public static final EncodeHintType ERROR_CORRECTION = new EncodeHintType();
|
public static final EncodeHintType ERROR_CORRECTION = new EncodeHintType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies what character encoding to use where applicable (type String)
|
||||||
|
*/
|
||||||
|
public static final EncodeHintType CHARACTER_SET = new EncodeHintType();
|
||||||
|
|
||||||
private EncodeHintType() {
|
private EncodeHintType() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package com.google.zxing.qrcode.encoder;
|
package com.google.zxing.qrcode.encoder;
|
||||||
|
|
||||||
import com.google.zxing.WriterException;
|
import com.google.zxing.WriterException;
|
||||||
|
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.reedsolomon.GF256;
|
import com.google.zxing.common.reedsolomon.GF256;
|
||||||
|
@ -26,6 +27,7 @@ import com.google.zxing.qrcode.decoder.Mode;
|
||||||
import com.google.zxing.qrcode.decoder.Version;
|
import com.google.zxing.qrcode.decoder.Version;
|
||||||
|
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
import java.util.Hashtable;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,22 +80,36 @@ public final class Encoder {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode "bytes" with the error correction level "getECLevel". The encoding mode will be chosen
|
/**
|
||||||
// internally by chooseMode(). On success, store the result in "qrCode" and return true.
|
* Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen
|
||||||
// We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for
|
* internally by chooseMode(). On success, store the result in "qrCode".
|
||||||
// "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very
|
*
|
||||||
// strong error correction for this purpose.
|
* We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for
|
||||||
//
|
* "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very
|
||||||
// Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode()
|
* strong error correction for this purpose.
|
||||||
// with which clients can specify the encoding mode. For now, we don't need the functionality.
|
*
|
||||||
|
* Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode()
|
||||||
|
* with which clients can specify the encoding mode. For now, we don't need the functionality.
|
||||||
|
*/
|
||||||
public static void encode(String content, ErrorCorrectionLevel ecLevel, QRCode qrCode)
|
public static void encode(String content, ErrorCorrectionLevel ecLevel, QRCode qrCode)
|
||||||
throws WriterException {
|
throws WriterException {
|
||||||
|
encode(content, ecLevel, null, qrCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void encode(String content, ErrorCorrectionLevel ecLevel, Hashtable hints, QRCode qrCode)
|
||||||
|
throws WriterException {
|
||||||
|
|
||||||
|
String characterEncoding = hints == null ? null : (String) hints.get(EncodeHintType.CHARACTER_SET);
|
||||||
|
if (characterEncoding == null) {
|
||||||
|
characterEncoding = "ISO-8859-1";
|
||||||
|
}
|
||||||
|
|
||||||
// Step 1: Choose the mode (encoding).
|
// Step 1: Choose the mode (encoding).
|
||||||
Mode mode = chooseMode(content);
|
Mode mode = chooseMode(content);
|
||||||
|
|
||||||
// Step 2: Append "bytes" into "dataBits" in appropriate encoding.
|
// Step 2: Append "bytes" into "dataBits" in appropriate encoding.
|
||||||
BitVector dataBits = new BitVector();
|
BitVector dataBits = new BitVector();
|
||||||
appendBytes(content, mode, dataBits);
|
appendBytes(content, mode, dataBits, characterEncoding);
|
||||||
// Step 3: Initialize QR code that can contain "dataBits".
|
// Step 3: Initialize QR code that can contain "dataBits".
|
||||||
int numInputBytes = dataBits.sizeInBytes();
|
int numInputBytes = dataBits.sizeInBytes();
|
||||||
initQRCode(numInputBytes, ecLevel, mode, qrCode);
|
initQRCode(numInputBytes, ecLevel, mode, qrCode);
|
||||||
|
@ -127,8 +143,10 @@ public final class Encoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the code point of the table used in alphanumeric mode. Return -1 if there is no
|
/**
|
||||||
// corresponding code in the table.
|
* @return the code point of the table used in alphanumeric mode or
|
||||||
|
* -1 if there is no corresponding code in the table.
|
||||||
|
*/
|
||||||
static int getAlphanumericCode(int code) {
|
static int getAlphanumericCode(int code) {
|
||||||
if (code < ALPHANUMERIC_TABLE.length) {
|
if (code < ALPHANUMERIC_TABLE.length) {
|
||||||
return ALPHANUMERIC_TABLE[code];
|
return ALPHANUMERIC_TABLE[code];
|
||||||
|
@ -136,13 +154,13 @@ public final class Encoder {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Choose the best mode by examining the content.
|
/**
|
||||||
//
|
* Choose the best mode by examining the content.
|
||||||
// Note that this function does not return MODE_KANJI, as we cannot distinguish Shift_JIS from
|
*
|
||||||
// other encodings such as ISO-8859-1, from data bytes alone. For example "\xE0\xE0" can be
|
* Note that this function does not return MODE_KANJI, as we cannot distinguish Shift_JIS from
|
||||||
// interpreted as one character in Shift_JIS, but also two characters in ISO-8859-1.
|
* other encodings such as ISO-8859-1, from data bytes alone. For example "\xE0\xE0" can be
|
||||||
//
|
* interpreted as one character in Shift_JIS, but also two characters in ISO-8859-1.
|
||||||
// JAVAPORT: This MODE_KANJI limitation sounds like a problem for us.
|
*/
|
||||||
public static Mode chooseMode(String content) {
|
public static Mode chooseMode(String content) {
|
||||||
boolean hasNumeric = false;
|
boolean hasNumeric = false;
|
||||||
boolean hasAlphanumeric = false;
|
boolean hasAlphanumeric = false;
|
||||||
|
@ -181,8 +199,9 @@ public final class Encoder {
|
||||||
return bestMaskPattern;
|
return bestMaskPattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize "qrCode" according to "numInputBytes", "ecLevel", and "mode". On success, modify
|
/**
|
||||||
// "qrCode".
|
* Initialize "qrCode" according to "numInputBytes", "ecLevel", and "mode". On success, modify "qrCode".
|
||||||
|
*/
|
||||||
private static void initQRCode(int numInputBytes, ErrorCorrectionLevel ecLevel, Mode mode, QRCode qrCode)
|
private static void initQRCode(int numInputBytes, ErrorCorrectionLevel ecLevel, Mode mode, QRCode qrCode)
|
||||||
throws WriterException {
|
throws WriterException {
|
||||||
qrCode.setECLevel(ecLevel);
|
qrCode.setECLevel(ecLevel);
|
||||||
|
@ -219,7 +238,9 @@ public final class Encoder {
|
||||||
throw new WriterException("Cannot find proper rs block info (input data too big?)");
|
throw new WriterException("Cannot find proper rs block info (input data too big?)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
|
/**
|
||||||
|
* Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
|
||||||
|
*/
|
||||||
static void terminateBits(int numDataBytes, BitVector bits) throws WriterException {
|
static void terminateBits(int numDataBytes, BitVector bits) throws WriterException {
|
||||||
int capacity = numDataBytes << 3;
|
int capacity = numDataBytes << 3;
|
||||||
if (bits.size() > capacity) {
|
if (bits.size() > capacity) {
|
||||||
|
@ -255,9 +276,11 @@ public final class Encoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get number of data bytes and number of error correction bytes for block id "blockID". Store
|
/**
|
||||||
// the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
|
* Get number of data bytes and number of error correction bytes for block id "blockID". Store
|
||||||
// JISX0510:2004 (p.30)
|
* the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
|
||||||
|
* JISX0510:2004 (p.30)
|
||||||
|
*/
|
||||||
static void getNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes,
|
static void getNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes,
|
||||||
int numRSBlocks, int blockID, int[] numDataBytesInBlock,
|
int numRSBlocks, int blockID, int[] numDataBytesInBlock,
|
||||||
int[] numECBytesInBlock) throws WriterException {
|
int[] numECBytesInBlock) throws WriterException {
|
||||||
|
@ -307,9 +330,10 @@ public final class Encoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interleave "bits" with corresponding error correction bytes. On success, store the result in
|
/**
|
||||||
// "result" and return true. The interleave rule is complicated. See 8.6
|
* Interleave "bits" with corresponding error correction bytes. On success, store the result in
|
||||||
// of JISX0510:2004 (p.37) for details.
|
* "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
|
||||||
|
*/
|
||||||
static void interleaveWithECBytes(BitVector bits, int numTotalBytes,
|
static void interleaveWithECBytes(BitVector bits, int numTotalBytes,
|
||||||
int numDataBytes, int numRSBlocks, BitVector result) throws WriterException {
|
int numDataBytes, int numRSBlocks, BitVector result) throws WriterException {
|
||||||
|
|
||||||
|
@ -386,15 +410,17 @@ public final class Encoder {
|
||||||
return ecBytes;
|
return ecBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append mode info. On success, store the result in "bits" and return true. On error, return
|
/**
|
||||||
// false.
|
* Append mode info. On success, store the result in "bits".
|
||||||
|
*/
|
||||||
static void appendModeInfo(Mode mode, BitVector bits) {
|
static void appendModeInfo(Mode mode, BitVector bits) {
|
||||||
bits.appendBits(mode.getBits(), 4);
|
bits.appendBits(mode.getBits(), 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Append length info. On success, store the result in "bits" and return true. On error, return
|
/**
|
||||||
// false.
|
* Append length info. On success, store the result in "bits".
|
||||||
|
*/
|
||||||
static void appendLengthInfo(int numLetters, int version, Mode mode, BitVector bits) throws WriterException {
|
static void appendLengthInfo(int numLetters, int version, Mode mode, BitVector bits) throws WriterException {
|
||||||
int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version));
|
int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version));
|
||||||
if (numLetters > ((1 << numBits) - 1)) {
|
if (numLetters > ((1 << numBits) - 1)) {
|
||||||
|
@ -403,15 +429,16 @@ public final class Encoder {
|
||||||
bits.appendBits(numLetters, numBits);
|
bits.appendBits(numLetters, numBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits"
|
/**
|
||||||
// and return true.
|
* Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".
|
||||||
static void appendBytes(String content, Mode mode, BitVector bits) throws WriterException {
|
*/
|
||||||
|
static void appendBytes(String content, Mode mode, BitVector bits, String encoding) throws WriterException {
|
||||||
if (mode.equals(Mode.NUMERIC)) {
|
if (mode.equals(Mode.NUMERIC)) {
|
||||||
appendNumericBytes(content, bits);
|
appendNumericBytes(content, bits);
|
||||||
} else if (mode.equals(Mode.ALPHANUMERIC)) {
|
} else if (mode.equals(Mode.ALPHANUMERIC)) {
|
||||||
appendAlphanumericBytes(content, bits);
|
appendAlphanumericBytes(content, bits);
|
||||||
} else if (mode.equals(Mode.BYTE)) {
|
} else if (mode.equals(Mode.BYTE)) {
|
||||||
append8BitBytes(content, bits);
|
append8BitBytes(content, bits, encoding);
|
||||||
} else if (mode.equals(Mode.KANJI)) {
|
} else if (mode.equals(Mode.KANJI)) {
|
||||||
appendKanjiBytes(content, bits);
|
appendKanjiBytes(content, bits);
|
||||||
} else {
|
} else {
|
||||||
|
@ -467,10 +494,10 @@ public final class Encoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void append8BitBytes(String content, BitVector bits) throws WriterException {
|
static void append8BitBytes(String content, BitVector bits, String encoding) throws WriterException {
|
||||||
byte[] bytes;
|
byte[] bytes;
|
||||||
try {
|
try {
|
||||||
bytes = content.getBytes("ISO-8859-1"); // TODO support specifying encoding?
|
bytes = content.getBytes(encoding);
|
||||||
} catch (UnsupportedEncodingException uee) {
|
} catch (UnsupportedEncodingException uee) {
|
||||||
throw new WriterException(uee.toString());
|
throw new WriterException(uee.toString());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue