mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Remove Debug and switch to eceptions in Encoder / Writer API
git-svn-id: https://zxing.googlecode.com/svn/trunk@740 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
7b0a66862d
commit
65be5295c8
|
@ -24,6 +24,10 @@ package com.google.zxing;
|
|||
*/
|
||||
public final class WriterException extends Exception {
|
||||
|
||||
public WriterException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public WriterException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
|
|
@ -60,11 +60,8 @@ public final class QRCodeWriter implements Writer {
|
|||
// TODO: Check hints for error correction level instead of hardcoding
|
||||
int errorCorrectionLevel = QRCode.EC_LEVEL_L;
|
||||
QRCode code = new QRCode();
|
||||
if (Encoder.Encode(new ByteArray(contents), errorCorrectionLevel, code)) {
|
||||
return renderResult(code, width, height);
|
||||
} else {
|
||||
throw new WriterException("Could not generate a QR Code");
|
||||
}
|
||||
Encoder.Encode(new ByteArray(contents), errorCorrectionLevel, code);
|
||||
return renderResult(code, width, height);
|
||||
}
|
||||
|
||||
// Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses
|
||||
|
|
|
@ -39,8 +39,9 @@ public final class BitVector {
|
|||
|
||||
// Return the bit value at "index".
|
||||
public int at(final int index) {
|
||||
Debug.DCHECK_LE(0, index);
|
||||
Debug.DCHECK_LT(index, sizeInBits);
|
||||
if (index < 0 || index >= sizeInBits) {
|
||||
throw new IllegalArgumentException("Bad index: " + index);
|
||||
}
|
||||
final int value = array[index >> 3] & 0xff;
|
||||
return (value >> (7 - (index & 0x7))) & 1;
|
||||
}
|
||||
|
@ -59,7 +60,9 @@ public final class BitVector {
|
|||
|
||||
// Append one bit to the bit vector.
|
||||
public void AppendBit(final int bit) {
|
||||
Debug.DCHECK(bit == 0 || bit == 1);
|
||||
if (!(bit == 0 || bit == 1)) {
|
||||
throw new IllegalArgumentException("Bad bit");
|
||||
}
|
||||
final int num_bits_in_last_byte = sizeInBits & 0x7;
|
||||
// We'll expand array if we don't have bits in the last byte.
|
||||
if (num_bits_in_last_byte == 0) {
|
||||
|
@ -79,7 +82,9 @@ public final class BitVector {
|
|||
// - AppendBits(0x00, 4) adds 0000.
|
||||
// - AppendBits(0xff, 8) adds 11111111.
|
||||
public void AppendBits(final int value, final int num_bits) {
|
||||
Debug.DCHECK(num_bits >= 0 && num_bits <= 32);
|
||||
if (num_bits < 0 || num_bits > 32) {
|
||||
throw new IllegalArgumentException("Num bits must be between 0 and 32");
|
||||
}
|
||||
int num_bits_left = num_bits;
|
||||
while (num_bits_left > 0) {
|
||||
// Optimization for byte-oriented appending.
|
||||
|
@ -105,7 +110,9 @@ public final class BitVector {
|
|||
|
||||
// Modify the bit vector by XOR'ing with "other"
|
||||
public void XOR(final BitVector other) {
|
||||
Debug.DCHECK_EQ(sizeInBits, other.size());
|
||||
if (sizeInBits != other.size()) {
|
||||
throw new IllegalArgumentException("BitVector sizes don't match");
|
||||
}
|
||||
int sizeInBytes = (sizeInBits + 7) >> 3;
|
||||
for (int i = 0; i < sizeInBytes; ++i) {
|
||||
// The last byte could be incomplete (i.e. not have 8 bits in
|
||||
|
@ -123,7 +130,7 @@ public final class BitVector {
|
|||
} else if (at(i) == 1) {
|
||||
result.append("1");
|
||||
} else {
|
||||
Debug.DCHECK(false);
|
||||
throw new IllegalArgumentException("Byte isn't 0 or 1");
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.qrcode.encoder;
|
||||
|
||||
/**
|
||||
* JAVAPORT: Equivalent methods to the C++ versions. It's debateable whether these should throw or
|
||||
* assert. We can revisit that decision, or remove these throughout the code later.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public class Debug {
|
||||
|
||||
public static void LOG_ERROR(String message) {
|
||||
// Can't use IllegalStateException unfortunately in J2ME
|
||||
// TODO do something else with this anyway
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
|
||||
public static void LOG_INFO(String message) {
|
||||
// Chris M -- throwing RuntimeException in an INFO function seems terribly
|
||||
// strange and violates my assumptions about logging information. Even
|
||||
// ERROR is borderline since it's effectively going to go unchecked by most
|
||||
// callers. There has to be a more general way to do this.
|
||||
// throw new RuntimeException(message);
|
||||
}
|
||||
|
||||
public static void DCHECK(boolean condition) {
|
||||
if (!condition) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void DCHECK_LT(int a, int b) {
|
||||
DCHECK(a < b);
|
||||
}
|
||||
|
||||
public static void DCHECK_LE(int a, int b) {
|
||||
DCHECK(a <= b);
|
||||
}
|
||||
|
||||
public static void DCHECK_GT(int a, int b) {
|
||||
DCHECK(a > b);
|
||||
}
|
||||
|
||||
public static void DCHECK_GE(int a, int b) {
|
||||
DCHECK(a >= b);
|
||||
}
|
||||
|
||||
public static void DCHECK_EQ(int a, int b) {
|
||||
DCHECK(a == b);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,6 +20,7 @@ import com.google.zxing.common.ByteMatrix;
|
|||
import com.google.zxing.common.ByteArray;
|
||||
import com.google.zxing.common.reedsolomon.GF256;
|
||||
import com.google.zxing.common.reedsolomon.ReedSolomonEncoder;
|
||||
import com.google.zxing.WriterException;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
|
@ -41,8 +42,8 @@ public final class Encoder {
|
|||
|
||||
private static final class RSBlockInfo {
|
||||
|
||||
int num_bytes;
|
||||
int block_info[][];
|
||||
final int num_bytes;
|
||||
final int[][] block_info;
|
||||
|
||||
public RSBlockInfo(int num_bytes, int[][] block_info) {
|
||||
this.num_bytes = num_bytes;
|
||||
|
@ -99,8 +100,8 @@ public final class Encoder {
|
|||
|
||||
private static final class BlockPair {
|
||||
|
||||
private ByteArray dataBytes;
|
||||
private ByteArray errorCorrectionBytes;
|
||||
private final ByteArray dataBytes;
|
||||
private final ByteArray errorCorrectionBytes;
|
||||
|
||||
public BlockPair(ByteArray data, ByteArray errorCorrection) {
|
||||
dataBytes = data;
|
||||
|
@ -125,35 +126,25 @@ public final class Encoder {
|
|||
//
|
||||
// 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 boolean Encode(final ByteArray bytes, int ec_level, QRCode qr_code) {
|
||||
public static void Encode(final ByteArray bytes, int ec_level, QRCode qr_code) throws WriterException {
|
||||
// Step 1: Choose the mode (encoding).
|
||||
final int mode = ChooseMode(bytes);
|
||||
|
||||
// Step 2: Append "bytes" into "data_bits" in appropriate encoding.
|
||||
BitVector data_bits = new BitVector();
|
||||
if (!AppendBytes(bytes, mode, data_bits)) {
|
||||
return false;
|
||||
}
|
||||
AppendBytes(bytes, mode, data_bits);
|
||||
// Step 3: Initialize QR code that can contain "data_bits".
|
||||
final int num_input_bytes = data_bits.num_bytes();
|
||||
if (!InitQRCode(num_input_bytes, ec_level, mode, qr_code)) {
|
||||
return false;
|
||||
}
|
||||
InitQRCode(num_input_bytes, ec_level, mode, qr_code);
|
||||
|
||||
// Step 4: Build another bit vector that contains header and data.
|
||||
BitVector header_and_data_bits = new BitVector();
|
||||
if (!AppendModeInfo(qr_code.mode(), header_and_data_bits)) {
|
||||
return false;
|
||||
}
|
||||
if (!AppendLengthInfo(bytes.size(), qr_code.version(), qr_code.mode(), header_and_data_bits)) {
|
||||
return false;
|
||||
}
|
||||
AppendModeInfo(qr_code.mode(), header_and_data_bits);
|
||||
AppendLengthInfo(bytes.size(), qr_code.version(), qr_code.mode(), header_and_data_bits);
|
||||
header_and_data_bits.AppendBitVector(data_bits);
|
||||
|
||||
// Step 5: Terminate the bits properly.
|
||||
if (!TerminateBits(qr_code.num_data_bytes(), header_and_data_bits)) {
|
||||
return false;
|
||||
}
|
||||
TerminateBits(qr_code.num_data_bytes(), header_and_data_bits);
|
||||
|
||||
// Step 6: Interleave data bits with error correction code.
|
||||
BitVector final_bits = new BitVector();
|
||||
|
@ -164,10 +155,6 @@ public final class Encoder {
|
|||
ByteMatrix matrix = new ByteMatrix(qr_code.matrix_width(), qr_code.matrix_width());
|
||||
qr_code.set_mask_pattern(ChooseMaskPattern(final_bits, qr_code.ec_level(), qr_code.version(),
|
||||
matrix));
|
||||
if (qr_code.mask_pattern() == -1) {
|
||||
// There was an error.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 8. Build the matrix and set it to "qr_code".
|
||||
MatrixUtil.BuildMatrix(final_bits, qr_code.ec_level(), qr_code.version(),
|
||||
|
@ -175,10 +162,8 @@ public final class Encoder {
|
|||
qr_code.set_matrix(matrix);
|
||||
// Step 9. Make sure we have a valid QR Code.
|
||||
if (!qr_code.IsValid()) {
|
||||
Debug.LOG_ERROR("Invalid QR code: " + qr_code.toString());
|
||||
return false;
|
||||
throw new WriterException("Invalid QR code: " + qr_code.toString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the code point of the table used in alphanumeric mode. Return -1 if there is no
|
||||
|
@ -198,7 +183,7 @@ public final class Encoder {
|
|||
// 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 int ChooseMode(final ByteArray bytes) {
|
||||
public static int ChooseMode(final ByteArray bytes) throws WriterException {
|
||||
boolean has_numeric = false;
|
||||
boolean has_alphanumeric = false;
|
||||
boolean has_other = false;
|
||||
|
@ -220,15 +205,16 @@ public final class Encoder {
|
|||
return QRCode.MODE_NUMERIC;
|
||||
}
|
||||
// "bytes" must be empty to reach here.
|
||||
Debug.DCHECK(bytes.empty());
|
||||
if (!bytes.empty()) {
|
||||
throw new WriterException("Bytes left over");
|
||||
}
|
||||
return QRCode.MODE_8BIT_BYTE;
|
||||
}
|
||||
|
||||
private static int ChooseMaskPattern(final BitVector bits, int ec_level, int version,
|
||||
ByteMatrix matrix) {
|
||||
ByteMatrix matrix) throws WriterException {
|
||||
if (!QRCode.IsValidMatrixWidth(matrix.width())) {
|
||||
Debug.LOG_ERROR("Invalid matrix width: " + matrix.width());
|
||||
return -1;
|
||||
throw new WriterException("Invalid matrix width: " + matrix.width());
|
||||
}
|
||||
|
||||
int min_penalty = Integer.MAX_VALUE; // Lower penalty is better.
|
||||
|
@ -236,12 +222,9 @@ public final class Encoder {
|
|||
// We try all mask patterns to choose the best one.
|
||||
for (int i = 0; i < QRCode.kNumMaskPatterns; ++i) {
|
||||
final int mask_pattern = i;
|
||||
if (!MatrixUtil.BuildMatrix(bits, ec_level, version,
|
||||
mask_pattern, matrix)) {
|
||||
return -1;
|
||||
}
|
||||
MatrixUtil.BuildMatrix(bits, ec_level, version, mask_pattern, matrix);
|
||||
final int penalty = MaskUtil.CalculateMaskPenalty(matrix);
|
||||
Debug.LOG_INFO("mask_pattern: " + mask_pattern + ", " + "penalty: " + penalty);
|
||||
System.out.println("mask_pattern: " + mask_pattern + ", " + "penalty: " + penalty);
|
||||
if (penalty < min_penalty) {
|
||||
min_penalty = penalty;
|
||||
best_mask_pattern = mask_pattern;
|
||||
|
@ -252,13 +235,12 @@ public final class Encoder {
|
|||
|
||||
// Initialize "qr_code" according to "num_input_bytes", "ec_level", and "mode". On success, modify
|
||||
// "qr_code" and return true. On error, return false.
|
||||
private static boolean InitQRCode(int num_input_bytes, int ec_level, int mode, QRCode qr_code) {
|
||||
private static void InitQRCode(int num_input_bytes, int ec_level, int mode, QRCode qr_code) throws WriterException {
|
||||
qr_code.set_ec_level(ec_level);
|
||||
qr_code.set_mode(mode);
|
||||
|
||||
if (!QRCode.IsValidECLevel(ec_level)) {
|
||||
Debug.LOG_ERROR("Invalid EC level: " + ec_level);
|
||||
return false;
|
||||
throw new WriterException("Invalid EC level: " + ec_level);
|
||||
}
|
||||
|
||||
// In the following comments, we use numbers of Version 7-H.
|
||||
|
@ -285,19 +267,17 @@ public final class Encoder {
|
|||
qr_code.set_num_ec_bytes(num_bytes - num_data_bytes);
|
||||
// num_matrix_width = 21 + 6 * 4 = 45
|
||||
qr_code.set_matrix_width(21 + i * 4);
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Debug.LOG_ERROR("Cannot find proper rs block info (input data too big?)");
|
||||
return false;
|
||||
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).
|
||||
static boolean TerminateBits(int num_data_bytes, BitVector bits) {
|
||||
static void TerminateBits(int num_data_bytes, BitVector bits) throws WriterException {
|
||||
final int capacity = num_data_bytes * 8;
|
||||
if (bits.size() > capacity) {
|
||||
Debug.LOG_ERROR("data bits cannot fit in the QR Code" + bits.size() + " > " + capacity);
|
||||
return false;
|
||||
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.
|
||||
for (int i = 0; i < 4 && bits.size() < capacity; ++i) {
|
||||
|
@ -312,7 +292,9 @@ public final class Encoder {
|
|||
}
|
||||
}
|
||||
// Should be 8-bit aligned here.
|
||||
Debug.DCHECK_EQ(0, bits.size() % 8);
|
||||
if (bits.size() % 8 != 0) {
|
||||
throw new WriterException("Number of bits is not a multiple of 8");
|
||||
}
|
||||
// If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24).
|
||||
final int num_padding_bytes = num_data_bytes - bits.num_bytes();
|
||||
for (int i = 0; i < num_padding_bytes; ++i) {
|
||||
|
@ -322,8 +304,9 @@ public final class Encoder {
|
|||
bits.AppendBits(0x11, 8);
|
||||
}
|
||||
}
|
||||
Debug.DCHECK_EQ(bits.size(), capacity); // Should be same.
|
||||
return bits.size() == capacity;
|
||||
if (bits.size() != capacity) {
|
||||
throw new WriterException("Bits size does not equal capacity");
|
||||
}
|
||||
}
|
||||
|
||||
// Get number of data bytes and number of error correction bytes for block id "block_id". Store
|
||||
|
@ -331,8 +314,10 @@ public final class Encoder {
|
|||
// JISX0510:2004 (p.30)
|
||||
static void GetNumDataBytesAndNumECBytesForBlockID(int num_total_bytes, int num_data_bytes,
|
||||
int num_rs_blocks, int block_id, int[] num_data_bytes_in_block,
|
||||
int[] num_ec_bytes_in_block) {
|
||||
Debug.DCHECK_LT(block_id, num_rs_blocks);
|
||||
int[] num_ec_bytes_in_block) throws WriterException {
|
||||
if (block_id >= num_rs_blocks) {
|
||||
throw new WriterException("Block ID too large");
|
||||
}
|
||||
// num_rs_blocks_in_group2 = 196 % 5 = 1
|
||||
final int num_rs_blocks_in_group2 = num_total_bytes % num_rs_blocks;
|
||||
// num_rs_blocks_in_group1 = 5 - 1 = 4
|
||||
|
@ -353,15 +338,21 @@ public final class Encoder {
|
|||
num_data_bytes_in_group2;
|
||||
// Sanity checks.
|
||||
// 26 = 26
|
||||
Debug.DCHECK_EQ(num_ec_bytes_in_group1, num_ec_bytes_in_group2);
|
||||
if (num_ec_bytes_in_group1 != num_ec_bytes_in_group2) {
|
||||
throw new WriterException("EC bytes mismatch");
|
||||
}
|
||||
// 5 = 4 + 1.
|
||||
Debug.DCHECK_EQ(num_rs_blocks, num_rs_blocks_in_group1 + num_rs_blocks_in_group2);
|
||||
if (num_rs_blocks != num_rs_blocks_in_group1 + num_rs_blocks_in_group2) {
|
||||
throw new WriterException("RS blocks mismatch");
|
||||
}
|
||||
// 196 = (13 + 26) * 4 + (14 + 26) * 1
|
||||
Debug.DCHECK_EQ(num_total_bytes,
|
||||
if (num_total_bytes !=
|
||||
((num_data_bytes_in_group1 + num_ec_bytes_in_group1) *
|
||||
num_rs_blocks_in_group1) +
|
||||
((num_data_bytes_in_group2 + num_ec_bytes_in_group2) *
|
||||
num_rs_blocks_in_group2));
|
||||
num_rs_blocks_in_group2)) {
|
||||
throw new WriterException("Total bytes mismatch");
|
||||
}
|
||||
|
||||
if (block_id < num_rs_blocks_in_group1) {
|
||||
num_data_bytes_in_block[0] = num_data_bytes_in_group1;
|
||||
|
@ -375,11 +366,13 @@ public final class Encoder {
|
|||
// Interleave "bits" with corresponding error correction bytes. On success, store the result in
|
||||
// "result" and return true. On error, return false. The interleave rule is complicated. See 8.6
|
||||
// of JISX0510:2004 (p.37) for details.
|
||||
static boolean InterleaveWithECBytes(final BitVector bits, int num_total_bytes,
|
||||
int num_data_bytes, int num_rs_blocks, BitVector result) {
|
||||
static void InterleaveWithECBytes(final BitVector bits, int num_total_bytes,
|
||||
int num_data_bytes, int num_rs_blocks, BitVector result) throws WriterException {
|
||||
|
||||
// "bits" must have "num_data_bytes" bytes of data.
|
||||
Debug.DCHECK(bits.num_bytes() == num_data_bytes);
|
||||
if (bits.num_bytes() != num_data_bytes) {
|
||||
throw new WriterException("Number of bits and data bytes does not match");
|
||||
}
|
||||
|
||||
// Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll
|
||||
// store the divided data bytes blocks and error correction bytes blocks into "blocks".
|
||||
|
@ -406,7 +399,9 @@ public final class Encoder {
|
|||
max_num_ec_bytes = Math.max(max_num_ec_bytes, ec_bytes.size());
|
||||
data_bytes_offset += num_data_bytes_in_block[0];
|
||||
}
|
||||
Debug.DCHECK_EQ(num_data_bytes, data_bytes_offset);
|
||||
if (num_data_bytes != data_bytes_offset) {
|
||||
throw new WriterException("Data bytes does not match offset");
|
||||
}
|
||||
|
||||
// First, place data blocks.
|
||||
for (int i = 0; i < max_num_data_bytes; ++i) {
|
||||
|
@ -426,12 +421,10 @@ public final class Encoder {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (num_total_bytes == result.num_bytes()) { // Should be same.
|
||||
return true;
|
||||
}
|
||||
Debug.LOG_ERROR("Interleaving error: " + num_total_bytes + " and " + result.num_bytes() +
|
||||
if (num_total_bytes != result.num_bytes()) { // Should be same.
|
||||
throw new WriterException("Interleaving error: " + num_total_bytes + " and " + result.num_bytes() +
|
||||
" differ.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static ByteArray GenerateECBytes(ByteArray data_bytes, int num_ec_bytes_in_block) {
|
||||
|
@ -451,67 +444,60 @@ public final class Encoder {
|
|||
|
||||
// Append mode info. On success, store the result in "bits" and return true. On error, return
|
||||
// false.
|
||||
static boolean AppendModeInfo(int mode, BitVector bits) {
|
||||
static void AppendModeInfo(int mode, BitVector bits) throws WriterException {
|
||||
final int code = QRCode.GetModeCode(mode);
|
||||
if (code == -1) {
|
||||
Debug.LOG_ERROR("Invalid mode: " + mode);
|
||||
return false;
|
||||
}
|
||||
bits.AppendBits(code, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Append length info. On success, store the result in "bits" and return true. On error, return
|
||||
// false.
|
||||
static boolean AppendLengthInfo(int num_bytes, int version, int mode, BitVector bits) {
|
||||
static void AppendLengthInfo(int num_bytes, int version, int mode, BitVector bits) throws WriterException {
|
||||
int num_letters = num_bytes;
|
||||
// In Kanji mode, a letter is represented in two bytes.
|
||||
if (mode == QRCode.MODE_KANJI) {
|
||||
Debug.DCHECK_EQ(0, num_letters % 2);
|
||||
if (num_letters % 2 != 0) {
|
||||
throw new WriterException("Number of letters must be even");
|
||||
}
|
||||
num_letters /= 2;
|
||||
}
|
||||
|
||||
final int num_bits = QRCode.GetNumBitsForLength(version, mode);
|
||||
if (num_bits == -1) {
|
||||
Debug.LOG_ERROR("num_bits unset");
|
||||
return false;
|
||||
}
|
||||
if (num_letters > ((1 << num_bits) - 1)) {
|
||||
Debug.LOG_ERROR(num_letters + "is bigger than" + ((1 << num_bits) - 1));
|
||||
return false;
|
||||
throw new WriterException(num_letters + "is bigger than" + ((1 << num_bits) - 1));
|
||||
}
|
||||
bits.AppendBits(num_letters, num_bits);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits"
|
||||
// and return true. On error, return false.
|
||||
static boolean AppendBytes(final ByteArray bytes, int mode, BitVector bits) {
|
||||
static void AppendBytes(final ByteArray bytes, int mode, BitVector bits) throws WriterException {
|
||||
switch (mode) {
|
||||
case QRCode.MODE_NUMERIC:
|
||||
return AppendNumericBytes(bytes, bits);
|
||||
case QRCode.MODE_ALPHANUMERIC:
|
||||
return AppendAlphanumericBytes(bytes, bits);
|
||||
case QRCode.MODE_8BIT_BYTE:
|
||||
return Append8BitBytes(bytes, bits);
|
||||
case QRCode.MODE_KANJI:
|
||||
return AppendKanjiBytes(bytes, bits);
|
||||
default:
|
||||
AppendNumericBytes(bytes, bits);
|
||||
break;
|
||||
case QRCode.MODE_ALPHANUMERIC:
|
||||
AppendAlphanumericBytes(bytes, bits);
|
||||
break;
|
||||
case QRCode.MODE_8BIT_BYTE:
|
||||
Append8BitBytes(bytes, bits);
|
||||
break;
|
||||
case QRCode.MODE_KANJI:
|
||||
AppendKanjiBytes(bytes, bits);
|
||||
break;
|
||||
default:
|
||||
throw new WriterException("Invalid mode: " + mode);
|
||||
}
|
||||
Debug.LOG_ERROR("Invalid mode: " + mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Append "bytes" to "bits" using QRCode.MODE_NUMERIC mode. On success, store the result in "bits"
|
||||
// and return true. On error, return false.
|
||||
static boolean AppendNumericBytes(final ByteArray bytes, BitVector bits) {
|
||||
static void AppendNumericBytes(final ByteArray bytes, BitVector bits) throws WriterException {
|
||||
// Validate all the bytes first.
|
||||
for (int i = 0; i < bytes.size(); ++i) {
|
||||
int oneByte = bytes.at(i);
|
||||
if (oneByte < '0' || oneByte > '9') {
|
||||
return false;
|
||||
throw new WriterException("Non-digit found");
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < bytes.size();) {
|
||||
|
@ -533,21 +519,20 @@ public final class Encoder {
|
|||
++i;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Append "bytes" to "bits" using QRCode.MODE_ALPHANUMERIC mode. On success, store the result in
|
||||
// "bits" and return true. On error, return false.
|
||||
static boolean AppendAlphanumericBytes(final ByteArray bytes, BitVector bits) {
|
||||
static void AppendAlphanumericBytes(final ByteArray bytes, BitVector bits) throws WriterException {
|
||||
for (int i = 0; i < bytes.size();) {
|
||||
final int code1 = GetAlphanumericCode(bytes.at(i));
|
||||
if (code1 == -1) {
|
||||
return false;
|
||||
throw new WriterException();
|
||||
}
|
||||
if (i + 1 < bytes.size()) {
|
||||
final int code2 = GetAlphanumericCode(bytes.at(i + 1));
|
||||
if (code2 == -1) {
|
||||
return false;
|
||||
throw new WriterException();
|
||||
}
|
||||
// Encode two alphanumeric letters in 11 bits.
|
||||
bits.AppendBits(code1 * 45 + code2, 11);
|
||||
|
@ -558,29 +543,27 @@ public final class Encoder {
|
|||
++i;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Append "bytes" to "bits" using QRCode.MODE_8BIT_BYTE mode. On success, store the result in
|
||||
// "bits" and return true. On error, return false.
|
||||
static boolean Append8BitBytes(final ByteArray bytes, BitVector bits) {
|
||||
static void Append8BitBytes(final ByteArray bytes, BitVector bits) {
|
||||
for (int i = 0; i < bytes.size(); ++i) {
|
||||
bits.AppendBits(bytes.at(i), 8);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Append "bytes" to "bits" using QRCode.MODE_KANJI mode. On success, store the result in "bits"
|
||||
// and return true. On error, return false. See 8.4.5 of JISX0510:2004 (p.21) for how to encode
|
||||
// Kanji bytes.
|
||||
static boolean AppendKanjiBytes(final ByteArray bytes, BitVector bits) {
|
||||
static void AppendKanjiBytes(final ByteArray bytes, BitVector bits) throws WriterException {
|
||||
if (bytes.size() % 2 != 0) {
|
||||
// JAVAPORT: Our log implementation throws, which causes the unit test to fail.
|
||||
//Debug.LOG_ERROR("Invalid byte sequence: " + bytes);
|
||||
return false;
|
||||
throw new WriterException("Number of bytes must be even");
|
||||
}
|
||||
for (int i = 0; i < bytes.size(); i += 2) {
|
||||
Debug.DCHECK(IsValidKanji(bytes.at(i), bytes.at(i + 1)));
|
||||
if (!IsValidKanji(bytes.at(i), bytes.at(i + 1))) {
|
||||
throw new WriterException("Invalid Kanji at " + i);
|
||||
}
|
||||
final int code = (bytes.at(i) << 8) | bytes.at(i + 1);
|
||||
int subtracted = -1;
|
||||
if (code >= 0x8140 && code <= 0x9ffc) {
|
||||
|
@ -589,13 +572,11 @@ public final class Encoder {
|
|||
subtracted = code - 0xc140;
|
||||
}
|
||||
if (subtracted == -1) {
|
||||
Debug.LOG_ERROR("Invalid byte sequence: " + bytes);
|
||||
return false;
|
||||
throw new WriterException("Invalid byte sequence: " + bytes);
|
||||
}
|
||||
final int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
|
||||
bits.AppendBits(encoded, 13);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if "byte1" and "byte2" can compose a valid Kanji letter (2-byte Shift_JIS letter). The
|
||||
|
|
|
@ -40,7 +40,7 @@ public final class MaskUtil {
|
|||
public static int ApplyMaskPenaltyRule1(final ByteMatrix matrix) {
|
||||
final int penalty = (ApplyMaskPenaltyRule1Internal(matrix, true) +
|
||||
ApplyMaskPenaltyRule1Internal(matrix, false));
|
||||
Debug.LOG_INFO("\tApplyMaskPenaltyRule1: " + penalty);
|
||||
System.out.println("\tApplyMaskPenaltyRule1: " + penalty);
|
||||
return penalty;
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ public final class MaskUtil {
|
|||
}
|
||||
}
|
||||
}
|
||||
Debug.LOG_INFO("\tApplyMaskPenaltyRule2: " + penalty);
|
||||
System.out.println("\tApplyMaskPenaltyRule2: " + penalty);
|
||||
return penalty;
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ public final class MaskUtil {
|
|||
}
|
||||
}
|
||||
}
|
||||
Debug.LOG_INFO("\tApplyMaskPenaltyRule3: " + penalty);
|
||||
System.out.println("\tApplyMaskPenaltyRule3: " + penalty);
|
||||
return penalty;
|
||||
}
|
||||
|
||||
|
@ -144,14 +144,16 @@ public final class MaskUtil {
|
|||
final int num_total_cells = matrix.height() * matrix.width();
|
||||
double dark_ratio = (double) num_dark_cells / num_total_cells;
|
||||
final int penalty = Math.abs((int) (dark_ratio * 100 - 50)) / 5 * 10;
|
||||
Debug.LOG_INFO("\tApplyMaskPenaltyRule4: " + penalty);
|
||||
System.out.println("\tApplyMaskPenaltyRule4: " + penalty);
|
||||
return penalty;
|
||||
}
|
||||
|
||||
// Return the mask bit for "mask_pattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask
|
||||
// pattern conditions.
|
||||
public static int GetDataMaskBit(final int mask_pattern, final int x, final int y) {
|
||||
Debug.DCHECK(QRCode.IsValidMaskPattern(mask_pattern));
|
||||
if (!QRCode.IsValidMaskPattern(mask_pattern)) {
|
||||
throw new IllegalArgumentException("Invalid mask pattern");
|
||||
}
|
||||
switch (mask_pattern) {
|
||||
case 0:
|
||||
return ((y + x) % 2 == 0) ? 1 : 0;
|
||||
|
@ -169,11 +171,8 @@ public final class MaskUtil {
|
|||
return ((((y * x) % 2) + ((y * x) % 3)) % 2 == 0) ? 1 : 0;
|
||||
case 7:
|
||||
return ((((y * x) % 3) + ((y + x) % 2)) % 2 == 0) ? 1 : 0;
|
||||
default:
|
||||
;
|
||||
}
|
||||
Debug.LOG_ERROR("invalid mask pattern: " + mask_pattern);
|
||||
return -1;
|
||||
throw new IllegalArgumentException("invalid mask pattern: " + mask_pattern);
|
||||
}
|
||||
|
||||
// Helper function for ApplyMaskPenaltyRule1. We need this for doing this calculation in both
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.google.zxing.qrcode.encoder;
|
||||
|
||||
import com.google.zxing.common.ByteMatrix;
|
||||
import com.google.zxing.WriterException;
|
||||
|
||||
/**
|
||||
* @author satorux@google.com (Satoru Takabayashi) - creator
|
||||
|
@ -95,7 +96,7 @@ public final class MatrixUtil {
|
|||
};
|
||||
|
||||
// Type info cells at the left top corner.
|
||||
private static int kTypeInfoCoordinates[][] = {
|
||||
private static final int[][] kTypeInfoCoordinates = {
|
||||
{8, 0},
|
||||
{8, 1},
|
||||
{8, 2},
|
||||
|
@ -130,22 +131,16 @@ public final class MatrixUtil {
|
|||
|
||||
// Build 2D matrix of QR Code from "data_bits" with "ec_level", "version" and "mask_pattern". On
|
||||
// success, store the result in "matrix" and return true. On error, return false.
|
||||
public static boolean BuildMatrix(final BitVector data_bits, int ec_level, int version,
|
||||
int mask_pattern, ByteMatrix matrix) {
|
||||
public static void BuildMatrix(final BitVector data_bits, int ec_level, int version,
|
||||
int mask_pattern, ByteMatrix matrix) throws WriterException {
|
||||
MatrixUtil.ClearMatrix(matrix);
|
||||
if (!EmbedBasicPatterns(version, matrix)) {
|
||||
return false;
|
||||
}
|
||||
EmbedBasicPatterns(version, matrix);
|
||||
// Type information appear with any version.
|
||||
if (!EmbedTypeInfo(ec_level, mask_pattern, matrix)) {
|
||||
return false;
|
||||
}
|
||||
EmbedTypeInfo(ec_level, mask_pattern, matrix);
|
||||
// Version info appear if version >= 7.
|
||||
if (!MaybeEmbedVersionInfo(version, matrix)) {
|
||||
return false;
|
||||
}
|
||||
MaybeEmbedVersionInfo(version, matrix);
|
||||
// Data should be embedded at end.
|
||||
return EmbedDataBits(data_bits, mask_pattern, matrix);
|
||||
EmbedDataBits(data_bits, mask_pattern, matrix);
|
||||
}
|
||||
|
||||
// Embed basic patterns. On success, modify the matrix and return true. On error, return false.
|
||||
|
@ -154,7 +149,7 @@ public final class MatrixUtil {
|
|||
// - Timing patterns
|
||||
// - Dark dot at the left bottom corner
|
||||
// - Position adjustment patterns, if need be
|
||||
public static boolean EmbedBasicPatterns(int version, ByteMatrix matrix) {
|
||||
public static void EmbedBasicPatterns(int version, ByteMatrix matrix) throws WriterException {
|
||||
// Let's get started with embedding big squares at corners.
|
||||
EmbedPositionDetectionPatternsAndSeparators(matrix);
|
||||
// Then, embed the dark dot at the left bottom corner.
|
||||
|
@ -164,16 +159,12 @@ public final class MatrixUtil {
|
|||
MaybeEmbedPositionAdjustmentPatterns(version, matrix);
|
||||
// Timing patterns should be embedded after position adj. patterns.
|
||||
EmbedTimingPatterns(matrix);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Embed type information. On success, modify the matrix and return true. On error, return false.
|
||||
public static boolean EmbedTypeInfo(int ec_level, int mask_pattern, ByteMatrix matrix) {
|
||||
// Embed type information. On success, modify the matrix.
|
||||
public static void EmbedTypeInfo(int ec_level, int mask_pattern, ByteMatrix matrix) throws WriterException {
|
||||
BitVector type_info_bits = new BitVector();
|
||||
if (!MakeTypeInfoBits(ec_level, mask_pattern, type_info_bits)) {
|
||||
return false;
|
||||
}
|
||||
Debug.DCHECK_EQ(15, type_info_bits.size());
|
||||
MakeTypeInfoBits(ec_level, mask_pattern, type_info_bits);
|
||||
|
||||
for (int i = 0; i < type_info_bits.size(); ++i) {
|
||||
// Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
|
||||
|
@ -197,22 +188,18 @@ public final class MatrixUtil {
|
|||
matrix.set(y2, x2, bit);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Embed version information if need be. On success, modify the matrix and return true. On error,
|
||||
// return false. See 8.10 of JISX0510:2004 (p.47) for how to embed version information. Return
|
||||
// true on success, otherwise return false.
|
||||
public static boolean MaybeEmbedVersionInfo(int version, ByteMatrix matrix) {
|
||||
public static void MaybeEmbedVersionInfo(int version, ByteMatrix matrix) throws WriterException {
|
||||
if (version < 7) { // Version info is necessary if version >= 7.
|
||||
return true; // Don't need version info.
|
||||
return; // Don't need version info.
|
||||
}
|
||||
BitVector version_info_bits = new BitVector();
|
||||
if (!MakeVersionInfoBits(version, version_info_bits)) {
|
||||
return false;
|
||||
}
|
||||
MakeVersionInfoBits(version, version_info_bits);
|
||||
|
||||
Debug.DCHECK_EQ(18, version_info_bits.size());
|
||||
int bit_index = 6 * 3 - 1; // It will decrease from 17 to 0.
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
|
@ -225,13 +212,13 @@ public final class MatrixUtil {
|
|||
matrix.set(i, matrix.height() - 11 + j, bit);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Embed "data_bits" using "mask_pattern". On success, modify the matrix and return true. On
|
||||
// error, return false. For debugging purposes, it skips masking process if "mask_pattern" is -1.
|
||||
// See 8.7 of JISX0510:2004 (p.38) for how to embed data bits.
|
||||
public static boolean EmbedDataBits(final BitVector data_bits, int mask_pattern, ByteMatrix matrix) {
|
||||
public static void EmbedDataBits(final BitVector data_bits, int mask_pattern, ByteMatrix matrix)
|
||||
throws WriterException {
|
||||
int bit_index = 0;
|
||||
int direction = -1;
|
||||
// Start from the right bottom cell.
|
||||
|
@ -249,7 +236,7 @@ public final class MatrixUtil {
|
|||
if (!IsEmpty(matrix.get(y, xx))) {
|
||||
continue;
|
||||
}
|
||||
int bit = -1;
|
||||
int bit;
|
||||
if (bit_index < data_bits.size()) {
|
||||
bit = data_bits.at(bit_index);
|
||||
++bit_index;
|
||||
|
@ -258,12 +245,10 @@ public final class MatrixUtil {
|
|||
// in 8.4.9 of JISX0510:2004 (p. 24).
|
||||
bit = 0;
|
||||
}
|
||||
Debug.DCHECK(IsValidValue(bit));
|
||||
|
||||
// Skip masking if mask_pattern is -1.
|
||||
if (mask_pattern != -1) {
|
||||
final int mask = MaskUtil.GetDataMaskBit(mask_pattern, xx, y);
|
||||
Debug.DCHECK(mask == 0 || mask == 1);
|
||||
bit ^= mask;
|
||||
}
|
||||
matrix.set(y, xx, bit);
|
||||
|
@ -275,12 +260,9 @@ public final class MatrixUtil {
|
|||
x -= 2; // Move to the left.
|
||||
}
|
||||
// All bits should be consumed.
|
||||
if (bit_index < data_bits.size()) {
|
||||
Debug.LOG_ERROR("Not all bits consumed: " + bit_index + "/" + data_bits.size());
|
||||
return false;
|
||||
if (bit_index != data_bits.size()) {
|
||||
throw new WriterException("Not all bits consumed: " + bit_index + "/" + data_bits.size());
|
||||
}
|
||||
Debug.DCHECK_EQ(bit_index, data_bits.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the position of the most significant bit set (to one) in the "value". The most
|
||||
|
@ -338,13 +320,10 @@ public final class MatrixUtil {
|
|||
// Make bit vector of type information. On success, store the result in "bits" and return true.
|
||||
// On error, return false. Encode error correction level and mask pattern. See 8.9 of
|
||||
// JISX0510:2004 (p.45) for details.
|
||||
public static boolean MakeTypeInfoBits(int ec_level, final int mask_pattern, BitVector bits) {
|
||||
public static void MakeTypeInfoBits(int ec_level, final int mask_pattern, BitVector bits) throws WriterException {
|
||||
final int ec_code = QRCode.GetECLevelCode(ec_level);
|
||||
if (ec_code == -1) {
|
||||
return false;
|
||||
}
|
||||
if (!QRCode.IsValidMaskPattern(mask_pattern)) {
|
||||
return false;
|
||||
throw new WriterException("Invalid mask pattern");
|
||||
}
|
||||
final int type_info = (ec_code << 3) | mask_pattern;
|
||||
bits.AppendBits(type_info, 5);
|
||||
|
@ -357,24 +336,20 @@ public final class MatrixUtil {
|
|||
bits.XOR(mask_bits);
|
||||
|
||||
if (bits.size() != 15) { // Just in case.
|
||||
Debug.LOG_ERROR("should not happen but we got: " + bits.size());
|
||||
return false;
|
||||
throw new WriterException("should not happen but we got: " + bits.size());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Make bit vector of version information. On success, store the result in "bits" and return true.
|
||||
// On error, return false. See 8.10 of JISX0510:2004 (p.45) for details.
|
||||
public static boolean MakeVersionInfoBits(int version, BitVector bits) {
|
||||
public static void MakeVersionInfoBits(int version, BitVector bits) throws WriterException {
|
||||
bits.AppendBits(version, 6);
|
||||
final int bch_code = MatrixUtil.CalculateBCHCode(version, kVersionInfoPoly);
|
||||
bits.AppendBits(bch_code, 12);
|
||||
|
||||
if (bits.size() != 18) { // Just in case.
|
||||
Debug.LOG_ERROR("should not happen but we got: " + bits.size());
|
||||
return false;
|
||||
throw new WriterException("should not happen but we got: " + bits.size());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if "value" is empty.
|
||||
|
@ -389,18 +364,22 @@ public final class MatrixUtil {
|
|||
value == 1); // Dark (black).
|
||||
}
|
||||
|
||||
private static void EmbedTimingPatterns(ByteMatrix matrix) {
|
||||
private static void EmbedTimingPatterns(ByteMatrix matrix) throws WriterException {
|
||||
// -8 is for skipping position detection patterns (size 7), and two horizontal/vertical
|
||||
// separation patterns (size 1). Thus, 8 = 7 + 1.
|
||||
for (int i = 8; i < matrix.width() - 8; ++i) {
|
||||
final int bit = (i + 1) % 2;
|
||||
// Horizontal line.
|
||||
Debug.DCHECK(IsValidValue(matrix.get(6, i)));
|
||||
if (!IsValidValue(matrix.get(6, i))) {
|
||||
throw new WriterException();
|
||||
}
|
||||
if (IsEmpty(matrix.get(6, i))) {
|
||||
matrix.set(6, i, bit);
|
||||
}
|
||||
// Vertical line.
|
||||
Debug.DCHECK(IsValidValue(matrix.get(i, 6)));
|
||||
if (!IsValidValue(matrix.get(i, 6))) {
|
||||
throw new WriterException();
|
||||
}
|
||||
if (IsEmpty(matrix.get(i, 6))) {
|
||||
matrix.set(i, 6, bit);
|
||||
}
|
||||
|
@ -408,29 +387,37 @@ public final class MatrixUtil {
|
|||
}
|
||||
|
||||
// Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46)
|
||||
private static void EmbedDarkDotAtLeftBottomCorner(ByteMatrix matrix) {
|
||||
Debug.DCHECK(matrix.get(matrix.height() - 8, 8) != 0);
|
||||
private static void EmbedDarkDotAtLeftBottomCorner(ByteMatrix matrix) throws WriterException {
|
||||
if (matrix.get(matrix.height() - 8, 8) == 0) {
|
||||
throw new WriterException();
|
||||
}
|
||||
matrix.set(matrix.height() - 8, 8, 1);
|
||||
}
|
||||
|
||||
private static void EmbedHorizontalSeparationPattern(final int x_start, final int y_start,
|
||||
ByteMatrix matrix) {
|
||||
ByteMatrix matrix) throws WriterException {
|
||||
// We know the width and height.
|
||||
Debug.DCHECK_EQ(8, kHorizontalSeparationPattern[0].length);
|
||||
Debug.DCHECK_EQ(1, kHorizontalSeparationPattern.length);
|
||||
if (kHorizontalSeparationPattern[0].length != 8 || kHorizontalSeparationPattern.length != 1) {
|
||||
throw new WriterException("Bad horizontal separation pattern");
|
||||
}
|
||||
for (int x = 0; x < 8; ++x) {
|
||||
Debug.DCHECK(IsEmpty(matrix.get(y_start, x_start + x)));
|
||||
if (!IsEmpty(matrix.get(y_start, x_start + x))) {
|
||||
throw new WriterException();
|
||||
}
|
||||
matrix.set(y_start, x_start + x, kHorizontalSeparationPattern[0][x]);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmbedVerticalSeparationPattern(final int x_start, final int y_start,
|
||||
ByteMatrix matrix) {
|
||||
ByteMatrix matrix) throws WriterException {
|
||||
// We know the width and height.
|
||||
Debug.DCHECK_EQ(1, kVerticalSeparationPattern[0].length);
|
||||
Debug.DCHECK_EQ(7, kVerticalSeparationPattern.length);
|
||||
if (kVerticalSeparationPattern[0].length != 1 || kVerticalSeparationPattern.length != 7) {
|
||||
throw new WriterException("Bad vertical separation pattern");
|
||||
}
|
||||
for (int y = 0; y < 7; ++y) {
|
||||
Debug.DCHECK(IsEmpty(matrix.get(y_start + y, x_start)));
|
||||
if (!IsEmpty(matrix.get(y_start + y, x_start))) {
|
||||
throw new WriterException();
|
||||
}
|
||||
matrix.set(y_start + y, x_start, kVerticalSeparationPattern[y][0]);
|
||||
}
|
||||
}
|
||||
|
@ -439,33 +426,39 @@ public final class MatrixUtil {
|
|||
// almost identical, since we cannot write a function that takes 2D arrays in different sizes in
|
||||
// C/C++. We should live with the fact.
|
||||
private static void EmbedPositionAdjustmentPattern(final int x_start, final int y_start,
|
||||
ByteMatrix matrix) {
|
||||
ByteMatrix matrix) throws WriterException {
|
||||
// We know the width and height.
|
||||
Debug.DCHECK_EQ(5, kPositionAdjustmentPattern[0].length);
|
||||
Debug.DCHECK_EQ(5, kPositionAdjustmentPattern.length);
|
||||
if (kPositionAdjustmentPattern[0].length != 5 || kPositionAdjustmentPattern.length != 5) {
|
||||
throw new WriterException("Bad position adjustment");
|
||||
}
|
||||
for (int y = 0; y < 5; ++y) {
|
||||
for (int x = 0; x < 5; ++x) {
|
||||
Debug.DCHECK(IsEmpty(matrix.get(y_start + y, x_start + x)));
|
||||
if (!IsEmpty(matrix.get(y_start + y, x_start + x))) {
|
||||
throw new WriterException();
|
||||
}
|
||||
matrix.set(y_start + y, x_start + x, kPositionAdjustmentPattern[y][x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmbedPositionDetectionPattern(final int x_start, final int y_start,
|
||||
ByteMatrix matrix) {
|
||||
ByteMatrix matrix) throws WriterException {
|
||||
// We know the width and height.
|
||||
Debug.DCHECK_EQ(7, kPositionDetectionPattern[0].length);
|
||||
Debug.DCHECK_EQ(7, kPositionDetectionPattern.length);
|
||||
if (kPositionDetectionPattern[0].length != 7 || kPositionDetectionPattern.length != 7) {
|
||||
throw new WriterException("Bad position detection pattern");
|
||||
}
|
||||
for (int y = 0; y < 7; ++y) {
|
||||
for (int x = 0; x < 7; ++x) {
|
||||
Debug.DCHECK(IsEmpty(matrix.get(y_start + y, x_start + x)));
|
||||
if (!IsEmpty(matrix.get(y_start + y, x_start + x))) {
|
||||
throw new WriterException();
|
||||
}
|
||||
matrix.set(y_start + y, x_start + x, kPositionDetectionPattern[y][x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Embed position detection patterns and surrounding vertical/horizontal separators.
|
||||
private static void EmbedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) {
|
||||
private static void EmbedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) throws WriterException {
|
||||
// Embed three big squares at corners.
|
||||
final int pdp_width = kPositionDetectionPattern[0].length;
|
||||
// Left top corner.
|
||||
|
@ -497,7 +490,7 @@ public final class MatrixUtil {
|
|||
}
|
||||
|
||||
// Embed position adjustment patterns if need be.
|
||||
private static void MaybeEmbedPositionAdjustmentPatterns(final int version, ByteMatrix matrix) {
|
||||
private static void MaybeEmbedPositionAdjustmentPatterns(final int version, ByteMatrix matrix) throws WriterException {
|
||||
if (version < 2) { // The patterns appear if version >= 2
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.google.zxing.qrcode.encoder;
|
||||
|
||||
import com.google.zxing.common.ByteMatrix;
|
||||
import com.google.zxing.WriterException;
|
||||
|
||||
/**
|
||||
* @author satorux@google.com (Satoru Takabayashi) - creator
|
||||
|
@ -25,11 +26,11 @@ import com.google.zxing.common.ByteMatrix;
|
|||
public final class QRCode {
|
||||
|
||||
// Magic numbers.
|
||||
public static final int kMinVersion = 1;
|
||||
public static final int kMaxVersion = 40;
|
||||
private static final int kMinVersion = 1;
|
||||
private static final int kMaxVersion = 40;
|
||||
// For matrix width, see 7.3.1 of JISX0510:2004 (p.5).
|
||||
public static final int kMinMatrixWidth = 21; // Version 1
|
||||
public static final int kMaxMatrixWidth = 177; // Version 40 (21 + 4 * (40 -1)).
|
||||
private static final int kMinMatrixWidth = 21; // Version 1
|
||||
private static final int kMaxMatrixWidth = 177; // Version 40 (21 + 4 * (40 -1)).
|
||||
public static final int kNumMaskPatterns = 8;
|
||||
|
||||
// See table 3 of JISX0510:2004 (p.16)
|
||||
|
@ -128,7 +129,10 @@ public final class QRCode {
|
|||
public int at(int x, int y) {
|
||||
// The value must be zero or one.
|
||||
int value = matrix_.get(y, x);
|
||||
Debug.DCHECK(value == 0 || value == 1);
|
||||
if (!(value == 0 || value == 1)) {
|
||||
// this is really like an assert... not sure what better exception to use?
|
||||
throw new RuntimeException("Bad value");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -300,7 +304,7 @@ public final class QRCode {
|
|||
|
||||
// Return the code of error correction level. On error, return -1. The codes of error correction
|
||||
// levels are defined in the table 22 of JISX0510:2004 (p.45).
|
||||
public static int GetECLevelCode(final int ec_level) {
|
||||
public static int GetECLevelCode(final int ec_level) throws WriterException {
|
||||
switch (ec_level) {
|
||||
case QRCode.EC_LEVEL_L:
|
||||
return 1;
|
||||
|
@ -311,14 +315,13 @@ public final class QRCode {
|
|||
case QRCode.EC_LEVEL_H:
|
||||
return 2;
|
||||
default:
|
||||
break;
|
||||
throw new WriterException("Unknown EC level");
|
||||
}
|
||||
return -1; // Unknown error correction level.
|
||||
}
|
||||
|
||||
// Return the code of mode. On error, return -1. The codes of modes are defined in the table 2 of
|
||||
// JISX0510:2004 (p.16).
|
||||
public static int GetModeCode(final int mode) {
|
||||
public static int GetModeCode(final int mode) throws WriterException {
|
||||
switch (mode) {
|
||||
case QRCode.MODE_NUMERIC:
|
||||
return 1;
|
||||
|
@ -329,21 +332,18 @@ public final class QRCode {
|
|||
case QRCode.MODE_KANJI:
|
||||
return 8;
|
||||
default:
|
||||
break;
|
||||
throw new WriterException("Unknown mode: " + mode);
|
||||
}
|
||||
return -1; // Unknown mode.
|
||||
}
|
||||
|
||||
// Return the number of bits needed for representing the length info of QR Code with "version" and
|
||||
// "mode". On error, return -1.
|
||||
public static int GetNumBitsForLength(int version, int mode) {
|
||||
static int GetNumBitsForLength(int version, int mode) {
|
||||
if (!IsValidVersion(version)) {
|
||||
Debug.LOG_ERROR("Invalid version: " + version);
|
||||
return -1;
|
||||
throw new IllegalArgumentException("Invalid version: " + version);
|
||||
}
|
||||
if (!IsValidMode(mode)) {
|
||||
Debug.LOG_ERROR("Invalid mode: " + mode);
|
||||
return -1;
|
||||
throw new IllegalArgumentException("Invalid mode: " + mode);
|
||||
}
|
||||
if (version >= 1 && version <= 9) {
|
||||
return kNumBitsTable[0][mode];
|
||||
|
@ -351,10 +351,8 @@ public final class QRCode {
|
|||
return kNumBitsTable[1][mode];
|
||||
} else if (version >= 27 && version <= 40) {
|
||||
return kNumBitsTable[2][mode];
|
||||
} else {
|
||||
Debug.LOG_ERROR("Should not reach");
|
||||
}
|
||||
return -1;
|
||||
throw new IllegalArgumentException("Bad version: " + version);
|
||||
}
|
||||
|
||||
// Return true if the all values in the matrix are binary numbers. Otherwise, return false.
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.google.zxing.qrcode.encoder;
|
||||
|
||||
import com.google.zxing.common.ByteArray;
|
||||
import com.google.zxing.WriterException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
|
@ -25,7 +26,7 @@ import junit.framework.TestCase;
|
|||
*/
|
||||
public final class EncoderTestCase extends TestCase {
|
||||
|
||||
public void testGetAlphanumericCode() {
|
||||
public void testGetAlphanumericCode() throws WriterException {
|
||||
// The first ten code points are numbers.
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
assertEquals(i, Encoder.GetAlphanumericCode('0' + i));
|
||||
|
@ -53,7 +54,7 @@ public final class EncoderTestCase extends TestCase {
|
|||
assertEquals(-1, Encoder.GetAlphanumericCode('\0'));
|
||||
}
|
||||
|
||||
public void testChooseMode() {
|
||||
public void testChooseMode() throws WriterException {
|
||||
// Numeric mode.
|
||||
assertEquals(QRCode.MODE_NUMERIC, Encoder.ChooseMode(new ByteArray("0")));
|
||||
assertEquals(QRCode.MODE_NUMERIC, Encoder.ChooseMode(new ByteArray("0123456789")));
|
||||
|
@ -82,9 +83,9 @@ public final class EncoderTestCase extends TestCase {
|
|||
assertEquals(QRCode.MODE_8BIT_BYTE, Encoder.ChooseMode(new ByteArray(dat3)));
|
||||
}
|
||||
|
||||
public void testEncode() {
|
||||
public void testEncode() throws WriterException {
|
||||
QRCode qr_code = new QRCode();
|
||||
assertTrue(Encoder.Encode(new ByteArray("ABCDEF"), QRCode.EC_LEVEL_H, qr_code));
|
||||
Encoder.Encode(new ByteArray("ABCDEF"), QRCode.EC_LEVEL_H, qr_code);
|
||||
// The following is a valid QR Code that can be read by cell phones.
|
||||
String expected =
|
||||
"<<\n" +
|
||||
|
@ -123,85 +124,99 @@ public final class EncoderTestCase extends TestCase {
|
|||
assertEquals(expected, qr_code.toString());
|
||||
}
|
||||
|
||||
public void testAppendModeInfo() {
|
||||
public void testAppendModeInfo() throws WriterException {
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendModeInfo(QRCode.MODE_NUMERIC, bits));
|
||||
Encoder.AppendModeInfo(QRCode.MODE_NUMERIC, bits);
|
||||
assertEquals("0001", bits.toString());
|
||||
}
|
||||
|
||||
public void testAppendLengthInfo() {
|
||||
public void testAppendLengthInfo() throws WriterException {
|
||||
{
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendLengthInfo(1, // 1 letter (1/1).
|
||||
Encoder.AppendLengthInfo(1, // 1 letter (1/1).
|
||||
1, // version 1.
|
||||
QRCode.MODE_NUMERIC,
|
||||
bits));
|
||||
bits);
|
||||
assertEquals("0000000001", bits.toString()); // 10 bits.
|
||||
}
|
||||
{
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendLengthInfo(2, // 2 letters (2/1).
|
||||
Encoder.AppendLengthInfo(2, // 2 letters (2/1).
|
||||
10, // version 10.
|
||||
QRCode.MODE_ALPHANUMERIC,
|
||||
bits));
|
||||
bits);
|
||||
assertEquals("00000000010", bits.toString()); // 11 bits.
|
||||
}
|
||||
{
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendLengthInfo(255, // 255 letter (255/1).
|
||||
Encoder.AppendLengthInfo(255, // 255 letter (255/1).
|
||||
27, // version 27.
|
||||
QRCode.MODE_8BIT_BYTE,
|
||||
bits));
|
||||
bits);
|
||||
assertEquals("0000000011111111", bits.toString()); // 16 bits.
|
||||
}
|
||||
{
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendLengthInfo(1024, // 512 letters (1024/2).
|
||||
Encoder.AppendLengthInfo(1024, // 512 letters (1024/2).
|
||||
40, // version 40.
|
||||
QRCode.MODE_KANJI,
|
||||
bits));
|
||||
bits);
|
||||
assertEquals("001000000000", bits.toString()); // 12 bits.
|
||||
}
|
||||
}
|
||||
|
||||
public void testAppendBytes() {
|
||||
public void testAppendBytes() throws WriterException {
|
||||
{
|
||||
// Should use AppendNumericBytes.
|
||||
// 1 = 01 = 0001 in 4 bits.
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendBytes(new ByteArray("1"), QRCode.MODE_NUMERIC, bits));
|
||||
Encoder.AppendBytes(new ByteArray("1"), QRCode.MODE_NUMERIC, bits);
|
||||
assertEquals("0001" , bits.toString());
|
||||
// 'A' cannot be encoded in MODE_NUMERIC.
|
||||
assertFalse(Encoder.AppendBytes(new ByteArray("A"), QRCode.MODE_NUMERIC, bits));
|
||||
try {
|
||||
Encoder.AppendBytes(new ByteArray("A"), QRCode.MODE_NUMERIC, bits);
|
||||
fail("Should have thrown exception");
|
||||
} catch (WriterException we) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
{
|
||||
// Should use AppendAlphanumericBytes.
|
||||
// A = 10 = 0xa = 001010 in 6 bits
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendBytes(new ByteArray("A"), QRCode.MODE_ALPHANUMERIC, bits));
|
||||
Encoder.AppendBytes(new ByteArray("A"), QRCode.MODE_ALPHANUMERIC, bits);
|
||||
assertEquals("001010" , bits.toString());
|
||||
// Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
|
||||
assertFalse(Encoder.AppendBytes(new ByteArray("a"), QRCode.MODE_ALPHANUMERIC, bits));
|
||||
try {
|
||||
Encoder.AppendBytes(new ByteArray("a"), QRCode.MODE_ALPHANUMERIC, bits);
|
||||
} catch (WriterException we) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
{
|
||||
// Should use Append8BitBytes.
|
||||
// 0x61, 0x62, 0x63
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendBytes(new ByteArray("abc"), QRCode.MODE_8BIT_BYTE, bits));
|
||||
Encoder.AppendBytes(new ByteArray("abc"), QRCode.MODE_8BIT_BYTE, bits);
|
||||
assertEquals("01100001" + "01100010" + "01100011", bits.toString());
|
||||
// Anything can be encoded in QRCode.MODE_8BIT_BYTE.
|
||||
byte[] bytes = {0x00};
|
||||
assertTrue(Encoder.AppendBytes(new ByteArray(bytes), QRCode.MODE_8BIT_BYTE, bits));
|
||||
Encoder.AppendBytes(new ByteArray(bytes), QRCode.MODE_8BIT_BYTE, bits);
|
||||
}
|
||||
{
|
||||
// Should use AppendKanjiBytes.
|
||||
// 0x93, 0x5f
|
||||
BitVector bits = new BitVector();
|
||||
byte[] bytes = {(byte)0x93,0x5f};
|
||||
assertTrue(Encoder.AppendBytes(new ByteArray(bytes), QRCode.MODE_KANJI, bits));
|
||||
Encoder.AppendBytes(new ByteArray(bytes), QRCode.MODE_KANJI, bits);
|
||||
assertEquals("0110110011111", bits.toString());
|
||||
// ASCII characters can not be encoded in QRCode.MODE_KANJI.
|
||||
assertFalse(Encoder.AppendBytes(new ByteArray("a"), QRCode.MODE_KANJI, bits));
|
||||
|
||||
try {
|
||||
Encoder.AppendBytes(new ByteArray("a"), QRCode.MODE_KANJI, bits);
|
||||
} catch (WriterException we) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,49 +224,49 @@ public final class EncoderTestCase extends TestCase {
|
|||
// TODO: should be implemented.
|
||||
}
|
||||
|
||||
public void testTerminateBits() {
|
||||
public void testTerminateBits() throws WriterException {
|
||||
{
|
||||
BitVector v = new BitVector();
|
||||
assertTrue(Encoder.TerminateBits(0, v));
|
||||
Encoder.TerminateBits(0, v);
|
||||
assertEquals("", v.toString());
|
||||
}
|
||||
{
|
||||
BitVector v = new BitVector();
|
||||
assertTrue(Encoder.TerminateBits(1, v));
|
||||
Encoder.TerminateBits(1, v);
|
||||
assertEquals("00000000", v.toString());
|
||||
}
|
||||
{
|
||||
BitVector v = new BitVector();
|
||||
v.AppendBits(0, 3); // Append 000
|
||||
assertTrue(Encoder.TerminateBits(1, v));
|
||||
Encoder.TerminateBits(1, v);
|
||||
assertEquals("00000000", v.toString());
|
||||
}
|
||||
{
|
||||
BitVector v = new BitVector();
|
||||
v.AppendBits(0, 5); // Append 00000
|
||||
assertTrue(Encoder.TerminateBits(1, v));
|
||||
Encoder.TerminateBits(1, v);
|
||||
assertEquals("00000000", v.toString());
|
||||
}
|
||||
{
|
||||
BitVector v = new BitVector();
|
||||
v.AppendBits(0, 8); // Append 00000000
|
||||
assertTrue(Encoder.TerminateBits(1, v));
|
||||
Encoder.TerminateBits(1, v);
|
||||
assertEquals("00000000", v.toString());
|
||||
}
|
||||
{
|
||||
BitVector v = new BitVector();
|
||||
assertTrue(Encoder.TerminateBits(2, v));
|
||||
Encoder.TerminateBits(2, v);
|
||||
assertEquals("0000000011101100", v.toString());
|
||||
}
|
||||
{
|
||||
BitVector v = new BitVector();
|
||||
v.AppendBits(0, 1); // Append 0
|
||||
assertTrue(Encoder.TerminateBits(3, v));
|
||||
Encoder.TerminateBits(3, v);
|
||||
assertEquals("000000001110110000010001", v.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetNumDataBytesAndNumECBytesForBlockID() {
|
||||
public void testGetNumDataBytesAndNumECBytesForBlockID() throws WriterException {
|
||||
int[] num_data_bytes = new int[1];
|
||||
int[] num_ec_bytes = new int[1];
|
||||
// Version 1-H.
|
||||
|
@ -287,7 +302,7 @@ public final class EncoderTestCase extends TestCase {
|
|||
assertEquals(30, num_ec_bytes[0]);
|
||||
}
|
||||
|
||||
public void testInterleaveWithECBytes() {
|
||||
public void testInterleaveWithECBytes() throws WriterException {
|
||||
{
|
||||
final byte[] data_bytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
|
||||
BitVector in = new BitVector();
|
||||
|
@ -295,7 +310,7 @@ public final class EncoderTestCase extends TestCase {
|
|||
in.AppendBits(data_byte, 8);
|
||||
}
|
||||
BitVector out = new BitVector();
|
||||
assertTrue(Encoder.InterleaveWithECBytes(in, 26, 9, 1, out));
|
||||
Encoder.InterleaveWithECBytes(in, 26, 9, 1, out);
|
||||
final byte[] expected = {
|
||||
// Data bytes.
|
||||
32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236,
|
||||
|
@ -325,7 +340,7 @@ public final class EncoderTestCase extends TestCase {
|
|||
in.AppendBits(data_byte, 8);
|
||||
}
|
||||
BitVector out = new BitVector();
|
||||
assertTrue(Encoder.InterleaveWithECBytes(in, 134, 62, 4, out));
|
||||
Encoder.InterleaveWithECBytes(in, 134, 62, 4, out);
|
||||
final byte[] expected = {
|
||||
// Data bytes.
|
||||
67, (byte)230, 54, 55, 70, (byte)247, 70, 71, 22, 7, 86, 87, 38, 23, 102, 103, 54, 39,
|
||||
|
@ -351,100 +366,108 @@ public final class EncoderTestCase extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public void testAppendNumericBytes() {
|
||||
public void testAppendNumericBytes() throws WriterException {
|
||||
{
|
||||
// 1 = 01 = 0001 in 4 bits.
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendNumericBytes(new ByteArray("1"), bits));
|
||||
Encoder.AppendNumericBytes(new ByteArray("1"), bits);
|
||||
assertEquals("0001" , bits.toString());
|
||||
}
|
||||
{
|
||||
// 12 = 0xc = 0001100 in 7 bits.
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendNumericBytes(new ByteArray("12"), bits));
|
||||
Encoder.AppendNumericBytes(new ByteArray("12"), bits);
|
||||
assertEquals("0001100" , bits.toString());
|
||||
}
|
||||
{
|
||||
// 123 = 0x7b = 0001111011 in 10 bits.
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendNumericBytes(new ByteArray("123"), bits));
|
||||
Encoder.AppendNumericBytes(new ByteArray("123"), bits);
|
||||
assertEquals("0001111011" , bits.toString());
|
||||
}
|
||||
{
|
||||
// 1234 = "123" + "4" = 0001111011 + 0100
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendNumericBytes(new ByteArray("1234"), bits));
|
||||
Encoder.AppendNumericBytes(new ByteArray("1234"), bits);
|
||||
assertEquals("0001111011" + "0100" , bits.toString());
|
||||
}
|
||||
{
|
||||
// Empty.
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendNumericBytes(new ByteArray(""), bits));
|
||||
Encoder.AppendNumericBytes(new ByteArray(""), bits);
|
||||
assertEquals("" , bits.toString());
|
||||
}
|
||||
{
|
||||
// Invalid data.
|
||||
BitVector bits = new BitVector();
|
||||
assertFalse(Encoder.AppendNumericBytes(new ByteArray("abc"), bits));
|
||||
try {
|
||||
Encoder.AppendNumericBytes(new ByteArray("abc"), bits);
|
||||
} catch (WriterException we) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testAppendAlphanumericBytes() {
|
||||
public void testAppendAlphanumericBytes() throws WriterException {
|
||||
{
|
||||
// A = 10 = 0xa = 001010 in 6 bits
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendAlphanumericBytes(new ByteArray("A"), bits));
|
||||
Encoder.AppendAlphanumericBytes(new ByteArray("A"), bits);
|
||||
assertEquals("001010" , bits.toString());
|
||||
}
|
||||
{
|
||||
// AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendAlphanumericBytes(new ByteArray("AB"), bits));
|
||||
Encoder.AppendAlphanumericBytes(new ByteArray("AB"), bits);
|
||||
assertEquals("00111001101", bits.toString());
|
||||
}
|
||||
{
|
||||
// ABC = "AB" + "C" = 00111001101 + 001100
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendAlphanumericBytes(new ByteArray("ABC"), bits));
|
||||
Encoder.AppendAlphanumericBytes(new ByteArray("ABC"), bits);
|
||||
assertEquals("00111001101" + "001100" , bits.toString());
|
||||
}
|
||||
{
|
||||
// Empty.
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.AppendAlphanumericBytes(new ByteArray(""), bits));
|
||||
Encoder.AppendAlphanumericBytes(new ByteArray(""), bits);
|
||||
assertEquals("" , bits.toString());
|
||||
}
|
||||
{
|
||||
// Invalid data.
|
||||
BitVector bits = new BitVector();
|
||||
assertFalse(Encoder.AppendAlphanumericBytes(new ByteArray("abc"), bits));
|
||||
try {
|
||||
Encoder.AppendAlphanumericBytes(new ByteArray("abc"), bits);
|
||||
} catch (WriterException we) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testAppend8BitBytes() {
|
||||
public void testAppend8BitBytes() throws WriterException {
|
||||
{
|
||||
// 0x61, 0x62, 0x63
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.Append8BitBytes(new ByteArray("abc"), bits));
|
||||
Encoder.Append8BitBytes(new ByteArray("abc"), bits);
|
||||
assertEquals("01100001" + "01100010" + "01100011", bits.toString());
|
||||
}
|
||||
{
|
||||
// Empty.
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(Encoder.Append8BitBytes(new ByteArray(""), bits));
|
||||
Encoder.Append8BitBytes(new ByteArray(""), bits);
|
||||
assertEquals("", bits.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Numbers are from page 21 of JISX0510:2004
|
||||
public void testAppendKanjiBytes() {
|
||||
public void testAppendKanjiBytes() throws WriterException {
|
||||
{
|
||||
BitVector bits = new BitVector();
|
||||
byte[] dat1 = {(byte)0x93,0x5f};
|
||||
assertTrue(Encoder.AppendKanjiBytes(new ByteArray(dat1), bits));
|
||||
Encoder.AppendKanjiBytes(new ByteArray(dat1), bits);
|
||||
assertEquals("0110110011111", bits.toString());
|
||||
byte[] dat2 = {(byte)0xe4,(byte)0xaa};
|
||||
assertTrue(Encoder.AppendKanjiBytes(new ByteArray(dat2), bits));
|
||||
Encoder.AppendKanjiBytes(new ByteArray(dat2), bits);
|
||||
assertEquals("0110110011111" + "1101010101010", bits.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.google.zxing.qrcode.encoder;
|
||||
|
||||
import com.google.zxing.common.ByteMatrix;
|
||||
import com.google.zxing.WriterException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
|
@ -48,7 +49,7 @@ public final class MatrixUtilTestCase extends TestCase {
|
|||
assertEquals(-1, matrix.get(1, 1));
|
||||
}
|
||||
|
||||
public void testEmbedBasicPatterns() {
|
||||
public void testEmbedBasicPatterns() throws WriterException {
|
||||
{
|
||||
// Version 1.
|
||||
String expected =
|
||||
|
@ -75,7 +76,7 @@ public final class MatrixUtilTestCase extends TestCase {
|
|||
" 1 1 1 1 1 1 1 0 \n";
|
||||
ByteMatrix matrix = new ByteMatrix(21, 21);
|
||||
MatrixUtil.ClearMatrix(matrix);
|
||||
assertTrue(MatrixUtil.EmbedBasicPatterns(1, matrix));
|
||||
MatrixUtil.EmbedBasicPatterns(1, matrix);
|
||||
assertEquals(expected, matrix.toString());
|
||||
}
|
||||
{
|
||||
|
@ -109,12 +110,12 @@ public final class MatrixUtilTestCase extends TestCase {
|
|||
" 1 1 1 1 1 1 1 0 \n";
|
||||
ByteMatrix matrix = new ByteMatrix(25, 25);
|
||||
MatrixUtil.ClearMatrix(matrix);
|
||||
assertTrue(MatrixUtil.EmbedBasicPatterns(2, matrix));
|
||||
MatrixUtil.EmbedBasicPatterns(2, matrix);
|
||||
assertEquals(expected, matrix.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void testEmbedTypeInfo() {
|
||||
public void testEmbedTypeInfo() throws WriterException {
|
||||
// Type info bits = 100000011001110.
|
||||
String expected =
|
||||
" 0 \n" +
|
||||
|
@ -140,12 +141,11 @@ public final class MatrixUtilTestCase extends TestCase {
|
|||
" 1 \n";
|
||||
ByteMatrix matrix = new ByteMatrix(21, 21);
|
||||
MatrixUtil.ClearMatrix(matrix);
|
||||
boolean info_okay = MatrixUtil.EmbedTypeInfo(QRCode.EC_LEVEL_M, 5, matrix);
|
||||
assertTrue(info_okay);
|
||||
MatrixUtil.EmbedTypeInfo(QRCode.EC_LEVEL_M, 5, matrix);
|
||||
assertEquals(expected, matrix.toString());
|
||||
}
|
||||
|
||||
public void testEmbedVersionInfo() {
|
||||
public void testEmbedVersionInfo() throws WriterException {
|
||||
// Version info bits = 000111 110010 010100
|
||||
String expected =
|
||||
" 0 0 1 \n" +
|
||||
|
@ -173,11 +173,11 @@ public final class MatrixUtilTestCase extends TestCase {
|
|||
// since 45x45 matrix is too big to depict.
|
||||
ByteMatrix matrix = new ByteMatrix(21, 21);
|
||||
MatrixUtil.ClearMatrix(matrix);
|
||||
assertTrue(MatrixUtil.MaybeEmbedVersionInfo(7, matrix));
|
||||
MatrixUtil.MaybeEmbedVersionInfo(7, matrix);
|
||||
assertEquals(expected, matrix.toString());
|
||||
}
|
||||
|
||||
public void testEmbedDataBits() {
|
||||
public void testEmbedDataBits() throws WriterException {
|
||||
// Cells other than basic patterns should be filled with zero.
|
||||
String expected =
|
||||
" 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n" +
|
||||
|
@ -205,11 +205,11 @@ public final class MatrixUtilTestCase extends TestCase {
|
|||
ByteMatrix matrix = new ByteMatrix(21, 21);
|
||||
MatrixUtil.ClearMatrix(matrix);
|
||||
MatrixUtil.EmbedBasicPatterns(1, matrix);
|
||||
assertTrue(MatrixUtil.EmbedDataBits(bits, -1, matrix));
|
||||
MatrixUtil.EmbedDataBits(bits, -1, matrix);
|
||||
assertEquals(expected, matrix.toString());
|
||||
}
|
||||
|
||||
public void testBuildMatrix() {
|
||||
public void testBuildMatrix() throws WriterException {
|
||||
// From http://www.swetake.com/qr/qr7.html
|
||||
String expected =
|
||||
" 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1\n" +
|
||||
|
@ -241,11 +241,11 @@ public final class MatrixUtilTestCase extends TestCase {
|
|||
bits.AppendBits(c, 8);
|
||||
}
|
||||
ByteMatrix matrix = new ByteMatrix(21, 21);
|
||||
assertTrue(MatrixUtil.BuildMatrix(bits,
|
||||
MatrixUtil.BuildMatrix(bits,
|
||||
QRCode.EC_LEVEL_H,
|
||||
1, // Version 1
|
||||
3, // Mask pattern 3
|
||||
matrix));
|
||||
matrix);
|
||||
}
|
||||
|
||||
public void testFindMSBSet() {
|
||||
|
@ -277,20 +277,20 @@ public final class MatrixUtilTestCase extends TestCase {
|
|||
|
||||
// We don't test a lot of cases in this function since we've already
|
||||
// tested them in TEST(CalculateBCHCode).
|
||||
public void testMakeVersionInfoBits() {
|
||||
public void testMakeVersionInfoBits() throws WriterException {
|
||||
// From Appendix D in JISX0510:2004 (p 68)
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(MatrixUtil.MakeVersionInfoBits(7, bits));
|
||||
MatrixUtil.MakeVersionInfoBits(7, bits);
|
||||
assertEquals("000111110010010100", bits.toString());
|
||||
}
|
||||
|
||||
// We don't test a lot of cases in this function since we've already
|
||||
// tested them in TEST(CalculateBCHCode).
|
||||
public void testMakeTypeInfoInfoBits() {
|
||||
public void testMakeTypeInfoInfoBits() throws WriterException {
|
||||
// From Appendix C in JISX0510:2004 (p 65)
|
||||
BitVector bits = new BitVector();
|
||||
assertTrue(MatrixUtil.MakeTypeInfoBits(QRCode.EC_LEVEL_M,
|
||||
5, bits));
|
||||
MatrixUtil.MakeTypeInfoBits(QRCode.EC_LEVEL_M,
|
||||
5, bits);
|
||||
assertEquals("100000011001110", bits.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.google.zxing.qrcode.encoder;
|
||||
|
||||
import com.google.zxing.common.ByteMatrix;
|
||||
import com.google.zxing.WriterException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
|
@ -208,19 +209,29 @@ public final class QRCodeTestCase extends TestCase {
|
|||
assertEquals("UNKNOWN", QRCode.ECLevelToString(QRCode.NUM_EC_LEVELS));
|
||||
}
|
||||
|
||||
public void testGetModeCode() {
|
||||
public void testGetModeCode() throws WriterException {
|
||||
assertEquals(1, QRCode.GetModeCode(QRCode.MODE_NUMERIC));
|
||||
assertEquals(2, QRCode.GetModeCode(QRCode.MODE_ALPHANUMERIC));
|
||||
assertEquals(4, QRCode.GetModeCode(QRCode.MODE_8BIT_BYTE));
|
||||
assertEquals(8, QRCode.GetModeCode(QRCode.MODE_KANJI));
|
||||
assertEquals(-1, QRCode.GetModeCode(QRCode.MODE_UNDEFINED));
|
||||
try {
|
||||
QRCode.GetModeCode(QRCode.MODE_UNDEFINED);
|
||||
fail("Should have thrown exception");
|
||||
} catch (WriterException we) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetECLevelCode() {
|
||||
public void testGetECLevelCode() throws WriterException {
|
||||
assertEquals(1, QRCode.GetECLevelCode(QRCode.EC_LEVEL_L));
|
||||
assertEquals(0, QRCode.GetECLevelCode(QRCode.EC_LEVEL_M));
|
||||
assertEquals(3, QRCode.GetECLevelCode(QRCode.EC_LEVEL_Q));
|
||||
assertEquals(2, QRCode.GetECLevelCode(QRCode.EC_LEVEL_H));
|
||||
assertEquals(-1, QRCode.GetECLevelCode(QRCode.EC_LEVEL_UNDEFINED));
|
||||
try {
|
||||
QRCode.GetECLevelCode(QRCode.EC_LEVEL_UNDEFINED);
|
||||
fail("Should have thrown exception");
|
||||
} catch (WriterException we) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
/**
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.qrcode.encoder;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
//#include "file/base/file.h"
|
||||
//#include "testing/base/gunit.h"
|
||||
//#include "testing/base/benchmark.h"
|
||||
//#include "wireless/qrcode/qrcode.h"
|
||||
//#include "wireless/qrcode/qrcode_encoder.h"
|
||||
//#include "wireless/qrcode/qrcode_renderer.h"
|
||||
|
||||
/**
|
||||
* @author satorux@google.com (Satoru Takabayashi) - creator
|
||||
* @author mysen@google.com (Chris Mysen) - ported from C++
|
||||
*/
|
||||
public final class RendererTestCase extends TestCase {
|
||||
// public void testRenderAsPNG() {
|
||||
// QRCode qr_code = new QRCode();
|
||||
// assertTrue(Encoder.Encode(new ByteArray("http://www.google.com/"),
|
||||
// QRCode.EC_LEVEL_M, qr_code));
|
||||
// String result;
|
||||
// assertTrue(Renderer.RenderAsPNG(qr_code, 3, result));
|
||||
// assertFalse(result.length() == 0);
|
||||
// // We don't test the result image in this test. We do that in
|
||||
// // RegressionTest().
|
||||
// }
|
||||
//
|
||||
// public void testRenderAsPNGFromData() {
|
||||
// QRCode qr_code = new QRCode();
|
||||
// assertTrue(Encoder.Encode(new ByteArray("http://www.google.com/"),
|
||||
// QRCode.EC_LEVEL_M, qr_code));
|
||||
// String result1;
|
||||
// assertTrue(Renderer.RenderAsPNG(qr_code, 3, result1));
|
||||
//
|
||||
// String result2;
|
||||
// assertTrue(Renderer.RenderAsPNGFromData("http://www.google.com/",
|
||||
// QRCode.EC_LEVEL_M, 3,
|
||||
// result2));
|
||||
// assertEquals(result1, result2);
|
||||
// }
|
||||
//
|
||||
// // ec_level comes from QRCode.EC_LEVEL_[LMQH]
|
||||
// static boolean Compare(final String bytes, final int ec_level,
|
||||
// final int cell_size, final String golden_base_name) {
|
||||
// String result;
|
||||
// assertTrue(Renderer.RenderAsPNGFromData(bytes, ec_level,
|
||||
// cell_size, result));
|
||||
// String golden_file_name = "test/data/qrcode_encode/" +
|
||||
// golden_base_name;
|
||||
// String golden;
|
||||
// File.ReadFileToStringOrDie(golden_file_name, golden);
|
||||
// return golden == result;
|
||||
// }
|
||||
//
|
||||
// // Golden images are generated with "qrcode_sample.cc". The images
|
||||
// // are checked with both eye balls and cell phones.
|
||||
// public void testRegressionTest() {
|
||||
// assertTrue(Compare("http://www.google.com/", QRCode.EC_LEVEL_M, 3,
|
||||
// "renderer-test-01.png"));
|
||||
// assertTrue(Compare("12345", QRCode.EC_LEVEL_L, 2,
|
||||
// "renderer-test-02.png"));
|
||||
// // Test in Katakana in Shift_JIS.
|
||||
// byte[] dat = {(byte)0x83,0x65,(byte)0x83,0x58,(byte)0x83,0x67};
|
||||
// assertTrue(Compare(new String(dat), QRCode.EC_LEVEL_H, 5,
|
||||
// "renderer-test-03.png"));
|
||||
// }
|
||||
}
|
Loading…
Reference in a new issue