Issue 361

git-svn-id: https://zxing.googlecode.com/svn/trunk@1268 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2010-03-30 22:53:34 +00:00
parent 0b74dfc7fe
commit 7410fd3082
33 changed files with 452 additions and 749 deletions

View file

@ -26,7 +26,7 @@ import com.google.zxing.client.android.R;
import com.google.zxing.client.result.AddressBookParsedResult;
import com.google.zxing.client.result.ParsedResult;
import com.google.zxing.client.result.ResultParser;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
import android.app.Activity;
import android.content.Intent;
@ -53,6 +53,8 @@ final class QRCodeEncoder {
private static final String TAG = "QRCodeEncoder";
private static final int WHITE = 0xFFFFFFFF;
private final Activity activity;
private String contents;
private String displayContents;
@ -327,17 +329,18 @@ final class QRCodeEncoder {
@Override
public void run() {
try {
ByteMatrix result = new MultiFormatWriter().encode(contents, format,
BitMatrix result = new MultiFormatWriter().encode(contents, format,
pixelResolution, pixelResolution);
int width = result.getWidth();
int height = result.getHeight();
byte[][] array = result.getArray();
int[] pixels = new int[width * height];
// All are 0, or black, by default
for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
int grey = array[y][x] & 0xff;
// pixels[y * width + x] = (0xff << 24) | (grey << 16) | (grey << 8) | grey;
pixels[y * width + x] = 0xff000000 | (0x00010101 * grey);
if (!result.get(x, y)) {
pixels[offset + x] = WHITE;
}
}
}

View file

@ -16,7 +16,7 @@
package com.google.zxing;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.oned.Code128Writer;
import com.google.zxing.oned.Code39Writer;
import com.google.zxing.oned.EAN13Writer;
@ -34,13 +34,13 @@ import java.util.Hashtable;
*/
public final class MultiFormatWriter implements Writer {
public ByteMatrix encode(String contents, BarcodeFormat format, int width,
public BitMatrix encode(String contents, BarcodeFormat format, int width,
int height) throws WriterException {
return encode(contents, format, width, height, null);
}
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
Writer writer;

View file

@ -16,7 +16,7 @@
package com.google.zxing;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
import java.util.Hashtable;
@ -36,7 +36,7 @@ public interface Writer {
* @param height The preferred height in pixels
* @return The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white)
*/
ByteMatrix encode(String contents, BarcodeFormat format, int width, int height)
BitMatrix encode(String contents, BarcodeFormat format, int width, int height)
throws WriterException;
/**
@ -48,7 +48,7 @@ public interface Writer {
* @param hints Additional parameters to supply to the encoder
* @return The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white)
*/
ByteMatrix encode(String contents, BarcodeFormat format, int width, int height, Hashtable hints)
BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Hashtable hints)
throws WriterException;
}

View file

@ -28,12 +28,14 @@ public final class BitArray {
// resulting binary at runtime on Android. If we find a solution to this, these should be changed
// back to private.
public int[] bits;
public final int size;
public int size;
public BitArray() {
this.size = 0;
this.bits = new int[1];
}
public BitArray(int size) {
if (size < 1) {
throw new IllegalArgumentException("size must be at least 1");
}
this.size = size;
this.bits = makeArray(size);
}
@ -42,6 +44,18 @@ public final class BitArray {
return size;
}
public int getSizeInBytes() {
return (size + 7) >> 3;
}
private void ensureCapacity(int size) {
if (size > bits.length << 5) {
int[] newBits = makeArray(size);
System.arraycopy(bits, 0, newBits, 0, bits.length);
this.bits = newBits;
}
}
/**
* @param i bit to get
* @return true iff bit i is set
@ -130,6 +144,69 @@ public final class BitArray {
return true;
}
public void appendBit(boolean bit) {
ensureCapacity(size + 1);
if (bit) {
bits[size >> 5] |= (1 << (size & 0x1F));
}
size++;
}
/**
* Appends the least-significant bits, from value, in order from most-significant to
* least-significant. For example, appending 6 bits from 0x000001E will append the bits
* 0, 1, 1, 1, 1, 0 in that order.
*/
public void appendBits(int value, int numBits) {
if (numBits < 0 || numBits > 32) {
throw new IllegalArgumentException("Num bits must be between 0 and 32");
}
ensureCapacity(size + numBits);
for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) {
appendBit(((value >> (numBitsLeft - 1)) & 0x01) == 1);
}
}
public void appendBitArray(BitArray other) {
int otherSize = other.getSize();
ensureCapacity(size + otherSize);
for (int i = 0; i < otherSize; i++) {
appendBit(other.get(i));
}
}
public void xor(BitArray other) {
if (bits.length != other.bits.length) {
throw new IllegalArgumentException("Sizes don't match");
}
for (int i = 0; i < bits.length; i++) {
// The last byte could be incomplete (i.e. not have 8 bits in
// it) but there is no problem since 0 XOR 0 == 0.
bits[i] ^= other.bits[i];
}
}
/**
*
* @param bitOffset first bit to start writing
* @param array array to write into. Bytes are written most-significant byte first. This is the opposite
* of the internal representation, which is exposed by {@link #getBitArray()}
* @param offset position in array to start writing
* @param numBytes how many bytes to write
*/
public void toBytes(int bitOffset, byte[] array, int offset, int numBytes) {
for (int i = 0; i < numBytes; i++) {
int theByte = 0;
for (int j = 0; j < 8; j++) {
if (get(bitOffset)) {
theByte |= 1 << (7 - j);
}
bitOffset++;
}
array[offset + i] = (byte) theByte;
}
}
/**
* @return underlying array of ints. The first element holds the first 32 bits, and the least
* significant bit is bit 0.
@ -153,11 +230,7 @@ public final class BitArray {
}
private static int[] makeArray(int size) {
int arraySize = size >> 5;
if ((size & 0x1F) != 0) {
arraySize++;
}
return new int[arraySize];
return new int[(size + 31) >> 5];
}
public String toString() {

View file

@ -50,11 +50,7 @@ public final class BitMatrix {
}
this.width = width;
this.height = height;
int rowSize = width >> 5;
if ((width & 0x1f) != 0) {
rowSize++;
}
this.rowSize = rowSize;
this.rowSize = (width + 31) >> 5;
bits = new int[rowSize * height];
}
@ -163,17 +159,32 @@ public final class BitMatrix {
return height;
}
/**
* This method is for compatibility with older code. It's only logical to call if the matrix
* is square, so I'm throwing if that's not the case.
*
* @return row/column dimension of this matrix
*/
public int getDimension() {
if (width != height) {
throw new RuntimeException("Can't call getDimension() on a non-square matrix");
public boolean equals(Object o) {
if (!(o instanceof BitMatrix)) {
return false;
}
return width;
BitMatrix other = (BitMatrix) o;
if (width != other.width || height != other.height ||
rowSize != other.rowSize || bits.length != other.bits.length) {
return false;
}
for (int i = 0; i < bits.length; i++) {
if (bits[i] != other.bits[i]) {
return false;
}
}
return true;
}
public int hashCode() {
int hash = width;
hash = 31 * hash + width;
hash = 31 * hash + height;
hash = 31 * hash + rowSize;
for (int i = 0; i < bits.length; i++) {
hash = 31 * hash + bits[i];
}
return hash;
}
public String toString() {

View file

@ -1,95 +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.common;
/**
* This class implements an array of unsigned bytes.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public final class ByteArray {
private static final int INITIAL_SIZE = 32;
private byte[] bytes;
private int size;
public ByteArray() {
bytes = null;
size = 0;
}
public ByteArray(int size) {
bytes = new byte[size];
this.size = size;
}
public ByteArray(byte[] byteArray) {
bytes = byteArray;
size = bytes.length;
}
/**
* Access an unsigned byte at location index.
* @param index The index in the array to access.
* @return The unsigned value of the byte as an int.
*/
public int at(int index) {
return bytes[index] & 0xff;
}
public void set(int index, int value) {
bytes[index] = (byte) value;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public void appendByte(int value) {
if (size == 0 || size >= bytes.length) {
int newSize = Math.max(INITIAL_SIZE, size << 1);
reserve(newSize);
}
bytes[size] = (byte) value;
size++;
}
public void reserve(int capacity) {
if (bytes == null || bytes.length < capacity) {
byte[] newArray = new byte[capacity];
if (bytes != null) {
System.arraycopy(bytes, 0, newArray, 0, bytes.length);
}
bytes = newArray;
}
}
// Copy count bytes from array source starting at offset.
public void set(byte[] source, int offset, int count) {
bytes = new byte[count];
size = count;
for (int x = 0; x < count; x++) {
bytes[x] = source[offset + x];
}
}
}

View file

@ -33,7 +33,7 @@ final class BitMatrixParser {
* @throws FormatException if dimension is < 10 or > 144 or not 0 mod 2
*/
BitMatrixParser(BitMatrix bitMatrix) throws FormatException {
int dimension = bitMatrix.getDimension();
int dimension = bitMatrix.getHeight();
if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0) {
throw FormatException.getFormatInstance();
}
@ -41,7 +41,7 @@ final class BitMatrixParser {
version = readVersion(bitMatrix);
this.mappingBitMatrix = extractDataRegion(bitMatrix);
// TODO(bbrown): Make this work for rectangular symbols
this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.getDimension());
this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.getHeight());
}
/**
@ -62,7 +62,7 @@ final class BitMatrixParser {
}
// TODO(bbrown): make this work for rectangular dimensions as well.
int numRows = bitMatrix.getDimension();
int numRows = bitMatrix.getHeight();
int numColumns = numRows;
return Version.getVersionForDimensions(numRows, numColumns);
@ -84,7 +84,7 @@ final class BitMatrixParser {
int row = 4;
int column = 0;
// TODO(bbrown): Data Matrix can be rectangular, assuming square for now
int numRows = mappingBitMatrix.getDimension();
int numRows = mappingBitMatrix.getHeight();
int numColumns = numRows;
boolean corner1Read = false;
@ -408,7 +408,7 @@ final class BitMatrixParser {
int symbolSizeColumns = version.getSymbolSizeColumns();
// TODO(bbrown): Make this work with rectangular codes
if (bitMatrix.getDimension() != symbolSizeRows) {
if (bitMatrix.getHeight() != symbolSizeRows) {
throw new IllegalArgumentException("Dimension of bitMarix must match the version size");
}

View file

@ -19,7 +19,7 @@ package com.google.zxing.oned;
import java.util.Hashtable;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
/**
* This object renders a CODE128 code as a {@link BitMatrix}.
@ -28,7 +28,7 @@ import com.google.zxing.common.ByteMatrix;
*/
public final class Code128Writer extends UPCEANWriter {
public ByteMatrix encode(String contents,
public BitMatrix encode(String contents,
BarcodeFormat format,
int width,
int height,

View file

@ -19,7 +19,7 @@ package com.google.zxing.oned;
import java.util.Hashtable;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
/**
* This object renders a CODE39 code as a {@link BitMatrix}.
@ -28,7 +28,7 @@ import com.google.zxing.common.ByteMatrix;
*/
public final class Code39Writer extends UPCEANWriter {
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
if (format != BarcodeFormat.CODE_39) {
throw new IllegalArgumentException("Can only encode CODE_39, but got " + format);

View file

@ -18,14 +18,13 @@ package com.google.zxing.oned;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
import java.util.Hashtable;
/**
* This object renders an EAN13 code as a ByteMatrix 2D array of greyscale
* values.
* This object renders an EAN13 code as a {@link BitMatrix}.
*
* @author aripollak@gmail.com (Ari Pollak)
*/
@ -37,7 +36,7 @@ public final class EAN13Writer extends UPCEANWriter {
(7 * 6) + // right bars
3; // end guard
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
if (format != BarcodeFormat.EAN_13) {
throw new IllegalArgumentException("Can only encode EAN_13, but got " + format);

View file

@ -18,13 +18,12 @@ package com.google.zxing.oned;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
import java.util.Hashtable;
/**
* This object renders an EAN8 code as a ByteMatrix 2D array of greyscale
* values.
* This object renders an EAN8 code as a {@link BitMatrix}.
*
* @author aripollak@gmail.com (Ari Pollak)
*/
@ -36,7 +35,7 @@ public final class EAN8Writer extends UPCEANWriter {
(7 * 4) + // right bars
3; // end guard
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
if (format != BarcodeFormat.EAN_8) {
throw new IllegalArgumentException("Can only encode EAN_8, but got "

View file

@ -19,7 +19,7 @@ package com.google.zxing.oned;
import java.util.Hashtable;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
/**
* This object renders a ITF code as a {@link BitMatrix}.
@ -28,7 +28,7 @@ import com.google.zxing.common.ByteMatrix;
*/
public final class ITFWriter extends UPCEANWriter {
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
if (format != BarcodeFormat.ITF) {
throw new IllegalArgumentException("Can only encode ITF, but got " + format);

View file

@ -19,7 +19,7 @@ package com.google.zxing.oned;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Writer;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
import java.util.Hashtable;
@ -31,12 +31,12 @@ import java.util.Hashtable;
*/
public abstract class UPCEANWriter implements Writer {
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height)
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height)
throws WriterException {
return encode(contents, format, width, height, null);
}
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
if (contents == null || contents.length() == 0) {
throw new IllegalArgumentException("Found empty contents");
@ -52,7 +52,7 @@ public abstract class UPCEANWriter implements Writer {
}
/** @return a byte array of horizontal pixels (0 = white, 1 = black) */
private static ByteMatrix renderResult(byte[] code, int width, int height) {
private static BitMatrix renderResult(byte[] code, int width, int height) {
int inputWidth = code.length;
// Add quiet zone on both sides
int fullWidth = inputWidth + (UPCEANReader.START_END_PATTERN.length << 1);
@ -62,37 +62,12 @@ public abstract class UPCEANWriter implements Writer {
int multiple = outputWidth / fullWidth;
int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
ByteMatrix output = new ByteMatrix(outputWidth, outputHeight);
byte[][] outputArray = output.getArray();
byte[] row = new byte[outputWidth];
// a. Write the white pixels at the left of each row
for (int x = 0; x < leftPadding; x++) {
row[x] = (byte) 255;
BitMatrix output = new BitMatrix(outputWidth, outputHeight);
for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
if (code[inputX] == 1) {
output.setRegion(outputX, 0, multiple, outputHeight);
}
// b. Write the contents of this row of the barcode
int offset = leftPadding;
for (int x = 0; x < inputWidth; x++) {
byte value = (code[x] == 1) ? 0 : (byte) 255;
for (int z = 0; z < multiple; z++) {
row[offset + z] = value;
}
offset += multiple;
}
// c. Write the white pixels at the right of each row
offset = leftPadding + (inputWidth * multiple);
for (int x = offset; x < outputWidth; x++) {
row[x] = (byte) 255;
}
// d. Write the completed row multiple times
for (int z = 0; z < outputHeight; z++) {
System.arraycopy(row, 0, outputArray[z], 0, outputWidth);
}
return output;
}

View file

@ -60,7 +60,7 @@ final class BitMatrixParser {
* @return an array of codewords.
*/
int[] readCodewords() throws FormatException {
int width = bitMatrix.getDimension();
int width = bitMatrix.getWidth();
// TODO should be a rectangular matrix
int height = width;
@ -186,7 +186,7 @@ final class BitMatrixParser {
*/
int processRow(int[] rowCounters, int rowNumber, int rowHeight, int[] codewords, int next)
throws FormatException {
int width = bitMatrix.getDimension();
int width = bitMatrix.getWidth();
int columnNumber = 0;
long symbol = 0;
for (int i = 0; i < width; i += MODULES_IN_SYMBOL) {

View file

@ -20,7 +20,8 @@ import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.Writer;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.encoder.ByteMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.encoder.Encoder;
import com.google.zxing.qrcode.encoder.QRCode;
@ -28,7 +29,7 @@ import com.google.zxing.qrcode.encoder.QRCode;
import java.util.Hashtable;
/**
* This object renders a QR Code as a ByteMatrix 2D array of greyscale values.
* This object renders a QR Code as a BitMatrix 2D array of greyscale values.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
@ -36,13 +37,13 @@ public final class QRCodeWriter implements Writer {
private static final int QUIET_ZONE_SIZE = 4;
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height)
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height)
throws WriterException {
return encode(contents, format, width, height, null);
}
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
if (contents == null || contents.length() == 0) {
@ -73,7 +74,7 @@ public final class QRCodeWriter implements Writer {
// Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses
// 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).
private static ByteMatrix renderResult(QRCode code, int width, int height) {
private static BitMatrix renderResult(QRCode code, int width, int height) {
ByteMatrix input = code.getMatrix();
int inputWidth = input.getWidth();
int inputHeight = input.getHeight();
@ -90,62 +91,18 @@ public final class QRCodeWriter implements Writer {
int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
int topPadding = (outputHeight - (inputHeight * multiple)) / 2;
ByteMatrix output = new ByteMatrix(outputWidth, outputHeight);
byte[][] outputArray = output.getArray();
BitMatrix output = new BitMatrix(outputWidth, outputHeight);
// We could be tricky and use the first row in each set of multiple as the temporary storage,
// instead of allocating this separate array.
byte[] row = new byte[outputWidth];
// 1. Write the white lines at the top
for (int y = 0; y < topPadding; y++) {
setRowColor(outputArray[y], (byte) 255);
}
// 2. Expand the QR image to the multiple
byte[][] inputArray = input.getArray();
for (int y = 0; y < inputHeight; y++) {
// a. Write the white pixels at the left of each row
for (int x = 0; x < leftPadding; x++) {
row[x] = (byte) 255;
}
// b. Write the contents of this row of the barcode
int offset = leftPadding;
for (int x = 0; x < inputWidth; x++) {
byte value = (inputArray[y][x] == 1) ? 0 : (byte) 255;
for (int z = 0; z < multiple; z++) {
row[offset + z] = value;
}
offset += multiple;
}
// c. Write the white pixels at the right of each row
offset = leftPadding + (inputWidth * multiple);
for (int x = offset; x < outputWidth; x++) {
row[x] = (byte) 255;
}
// d. Write the completed row multiple times
offset = topPadding + (y * multiple);
for (int z = 0; z < multiple; z++) {
System.arraycopy(row, 0, outputArray[offset + z], 0, outputWidth);
for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
// Write the contents of this row of the barcode
for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
if (input.get(inputX, inputY) == 1) {
output.setRegion(outputX, outputY, multiple, multiple);
}
}
// 3. Write the white lines at the bottom
int offset = topPadding + (inputHeight * multiple);
for (int y = offset; y < outputHeight; y++) {
setRowColor(outputArray[y], (byte) 255);
}
return output;
}
private static void setRowColor(byte[] row, byte value) {
for (int x = 0; x < row.length; x++) {
row[x] = value;
}
}
}

View file

@ -33,7 +33,7 @@ final class BitMatrixParser {
* @throws FormatException if dimension is not >= 21 and 1 mod 4
*/
BitMatrixParser(BitMatrix bitMatrix) throws FormatException {
int dimension = bitMatrix.getDimension();
int dimension = bitMatrix.getHeight();
if (dimension < 21 || (dimension & 0x03) != 1) {
throw FormatException.getFormatInstance();
}
@ -68,7 +68,7 @@ final class BitMatrixParser {
}
// Read the top-right/bottom-left pattern too
int dimension = bitMatrix.getDimension();
int dimension = bitMatrix.getHeight();
int formatInfoBits2 = 0;
int iMin = dimension - 8;
for (int i = dimension - 1; i >= iMin; i--) {
@ -98,7 +98,7 @@ final class BitMatrixParser {
return parsedVersion;
}
int dimension = bitMatrix.getDimension();
int dimension = bitMatrix.getHeight();
int provisionalVersion = (dimension - 17) >> 2;
if (provisionalVersion <= 6) {
@ -154,7 +154,7 @@ final class BitMatrixParser {
// Get the data mask for the format used in this QR Code. This will exclude
// some bits from reading as we wind through the bit matrix.
DataMask dataMask = DataMask.forReference((int) formatInfo.getDataMask());
int dimension = bitMatrix.getDimension();
int dimension = bitMatrix.getHeight();
dataMask.unmaskBitMatrix(bitMatrix, dimension);
BitMatrix functionPattern = version.buildFunctionPattern();

View file

@ -1,155 +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: This should be combined with BitArray in the future, although that class is not yet
* dynamically resizeable. This implementation is reasonable but there is a lot of function calling
* in loops I'd like to get rid of.
*
* @author satorux@google.com (Satoru Takabayashi) - creator
* @author dswitkin@google.com (Daniel Switkin) - ported from C++
*/
public final class BitVector {
private int sizeInBits;
private byte[] array;
// For efficiency, start out with some room to work.
private static final int DEFAULT_SIZE_IN_BYTES = 32;
public BitVector() {
sizeInBits = 0;
array = new byte[DEFAULT_SIZE_IN_BYTES];
}
// Return the bit value at "index".
public int at(int index) {
if (index < 0 || index >= sizeInBits) {
throw new IllegalArgumentException("Bad index: " + index);
}
int value = array[index >> 3] & 0xff;
return (value >> (7 - (index & 0x7))) & 1;
}
// Return the number of bits in the bit vector.
public int size() {
return sizeInBits;
}
// Return the number of bytes in the bit vector.
public int sizeInBytes() {
return (sizeInBits + 7) >> 3;
}
// Append one bit to the bit vector.
public void appendBit(int bit) {
if (!(bit == 0 || bit == 1)) {
throw new IllegalArgumentException("Bad bit");
}
int numBitsInLastByte = sizeInBits & 0x7;
// We'll expand array if we don't have bits in the last byte.
if (numBitsInLastByte == 0) {
appendByte(0);
sizeInBits -= 8;
}
// Modify the last byte.
array[sizeInBits >> 3] |= (bit << (7 - numBitsInLastByte));
++sizeInBits;
}
// Append "numBits" bits in "value" to the bit vector.
// REQUIRES: 0<= numBits <= 32.
//
// Examples:
// - appendBits(0x00, 1) adds 0.
// - appendBits(0x00, 4) adds 0000.
// - appendBits(0xff, 8) adds 11111111.
public void appendBits(int value, int numBits) {
if (numBits < 0 || numBits > 32) {
throw new IllegalArgumentException("Num bits must be between 0 and 32");
}
int numBitsLeft = numBits;
while (numBitsLeft > 0) {
// Optimization for byte-oriented appending.
if ((sizeInBits & 0x7) == 0 && numBitsLeft >= 8) {
int newByte = (value >> (numBitsLeft - 8)) & 0xff;
appendByte(newByte);
numBitsLeft -= 8;
} else {
int bit = (value >> (numBitsLeft - 1)) & 1;
appendBit(bit);
--numBitsLeft;
}
}
}
// Append "bits".
public void appendBitVector(BitVector bits) {
int size = bits.size();
for (int i = 0; i < size; ++i) {
appendBit(bits.at(i));
}
}
// Modify the bit vector by XOR'ing with "other"
public void xor(BitVector other) {
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
// it) but there is no problem since 0 XOR 0 == 0.
array[i] ^= other.array[i];
}
}
// Return String like "01110111" for debugging.
public String toString() {
StringBuffer result = new StringBuffer(sizeInBits);
for (int i = 0; i < sizeInBits; ++i) {
if (at(i) == 0) {
result.append('0');
} else if (at(i) == 1) {
result.append('1');
} else {
throw new IllegalArgumentException("Byte isn't 0 or 1");
}
}
return result.toString();
}
// Callers should not assume that array.length is the exact number of bytes needed to hold
// sizeInBits - it will typically be larger for efficiency.
public byte[] getArray() {
return array;
}
// Add a new byte to the end, possibly reallocating and doubling the size of the array if we've
// run out of room.
private void appendByte(int value) {
if ((sizeInBits >> 3) == array.length) {
byte[] newArray = new byte[(array.length << 1)];
System.arraycopy(array, 0, newArray, 0, array.length);
array = newArray;
}
array[sizeInBits >> 3] = (byte) value;
sizeInBits += 8;
}
}

View file

@ -16,23 +16,21 @@
package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteArray;
final class BlockPair {
private final ByteArray dataBytes;
private final ByteArray errorCorrectionBytes;
private final byte[] dataBytes;
private final byte[] errorCorrectionBytes;
BlockPair(ByteArray data, ByteArray errorCorrection) {
BlockPair(byte[] data, byte[] errorCorrection) {
dataBytes = data;
errorCorrectionBytes = errorCorrection;
}
public ByteArray getDataBytes() {
public byte[] getDataBytes() {
return dataBytes;
}
public ByteArray getErrorCorrectionBytes() {
public byte[] getErrorCorrectionBytes() {
return errorCorrectionBytes;
}

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.zxing.common;
package com.google.zxing.qrcode.encoder;
/**
* A class which wraps a 2D array of bytes. The default usage is signed. If you want to use it as a
@ -61,6 +61,10 @@ public final class ByteMatrix {
bytes[y][x] = (byte) value;
}
public void set(int x, int y, boolean value) {
bytes[y][x] = (byte) (value ? 1 : 0);
}
public void clear(byte value) {
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {

View file

@ -18,8 +18,7 @@ package com.google.zxing.qrcode.encoder;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteArray;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitArray;
import com.google.zxing.common.CharacterSetECI;
import com.google.zxing.common.reedsolomon.GF256;
import com.google.zxing.common.reedsolomon.ReedSolomonEncoder;
@ -91,14 +90,14 @@ public final class Encoder {
Mode mode = chooseMode(content, encoding);
// Step 2: Append "bytes" into "dataBits" in appropriate encoding.
BitVector dataBits = new BitVector();
BitArray dataBits = new BitArray();
appendBytes(content, mode, dataBits, encoding);
// Step 3: Initialize QR code that can contain "dataBits".
int numInputBytes = dataBits.sizeInBytes();
int numInputBytes = dataBits.getSizeInBytes();
initQRCode(numInputBytes, ecLevel, mode, qrCode);
// Step 4: Build another bit vector that contains header and data.
BitVector headerAndDataBits = new BitVector();
BitArray headerAndDataBits = new BitArray();
// Step 4.5: Append ECI message if applicable
if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.equals(encoding)) {
@ -110,15 +109,15 @@ public final class Encoder {
appendModeInfo(mode, headerAndDataBits);
int numLetters = mode.equals(Mode.BYTE) ? dataBits.sizeInBytes() : content.length();
int numLetters = mode.equals(Mode.BYTE) ? dataBits.getSizeInBytes() : content.length();
appendLengthInfo(numLetters, qrCode.getVersion(), mode, headerAndDataBits);
headerAndDataBits.appendBitVector(dataBits);
headerAndDataBits.appendBitArray(dataBits);
// Step 5: Terminate the bits properly.
terminateBits(qrCode.getNumDataBytes(), headerAndDataBits);
// Step 6: Interleave data bits with error correction code.
BitVector finalBits = new BitVector();
BitArray finalBits = new BitArray();
interleaveWithECBytes(headerAndDataBits, qrCode.getNumTotalBytes(), qrCode.getNumDataBytes(),
qrCode.getNumRSBlocks(), finalBits);
@ -201,7 +200,7 @@ public final class Encoder {
return true;
}
private static int chooseMaskPattern(BitVector bits, ErrorCorrectionLevel ecLevel, int version,
private static int chooseMaskPattern(BitArray bits, ErrorCorrectionLevel ecLevel, int version,
ByteMatrix matrix) throws WriterException {
int minPenalty = Integer.MAX_VALUE; // Lower penalty is better.
@ -261,41 +260,29 @@ public final class Encoder {
/**
* 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, BitArray bits) throws WriterException {
int capacity = numDataBytes << 3;
if (bits.size() > capacity) {
throw new WriterException("data bits cannot fit in the QR Code" + bits.size() + " > " +
if (bits.getSize() > capacity) {
throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " +
capacity);
}
for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) {
bits.appendBit(false);
}
// Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
// TODO: srowen says we can remove this for loop, since the 4 terminator bits are optional if
// the last byte has less than 4 bits left. So it amounts to padding the last byte with zeroes
// either way.
for (int i = 0; i < 4 && bits.size() < capacity; ++i) {
bits.appendBit(0);
}
int numBitsInLastByte = bits.size() % 8;
// If the last byte isn't 8-bit aligned, we'll add padding bits.
int numBitsInLastByte = bits.getSize() & 0x07;
if (numBitsInLastByte > 0) {
int numPaddingBits = 8 - numBitsInLastByte;
for (int i = 0; i < numPaddingBits; ++i) {
bits.appendBit(0);
for (int i = numBitsInLastByte; i < 8; i++) {
bits.appendBit(false);
}
}
// Should be 8-bit aligned here.
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).
int numPaddingBytes = numDataBytes - bits.sizeInBytes();
int numPaddingBytes = numDataBytes - bits.getSizeInBytes();
for (int i = 0; i < numPaddingBytes; ++i) {
if (i % 2 == 0) {
bits.appendBits(0xec, 8);
} else {
bits.appendBits(0x11, 8);
bits.appendBits(((i & 0x01) == 0) ? 0xEC : 0x11, 8);
}
}
if (bits.size() != capacity) {
if (bits.getSize() != capacity) {
throw new WriterException("Bits size does not equal capacity");
}
}
@ -358,11 +345,11 @@ public final class Encoder {
* Interleave "bits" with corresponding error correction bytes. On success, store the result in
* "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
*/
static void interleaveWithECBytes(BitVector bits, int numTotalBytes,
int numDataBytes, int numRSBlocks, BitVector result) throws WriterException {
static void interleaveWithECBytes(BitArray bits, int numTotalBytes,
int numDataBytes, int numRSBlocks, BitArray result) throws WriterException {
// "bits" must have "getNumDataBytes" bytes of data.
if (bits.sizeInBytes() != numDataBytes) {
if (bits.getSizeInBytes() != numDataBytes) {
throw new WriterException("Number of bits and data bytes does not match");
}
@ -382,13 +369,14 @@ public final class Encoder {
numTotalBytes, numDataBytes, numRSBlocks, i,
numDataBytesInBlock, numEcBytesInBlock);
ByteArray dataBytes = new ByteArray();
dataBytes.set(bits.getArray(), dataBytesOffset, numDataBytesInBlock[0]);
ByteArray ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]);
int size = numDataBytesInBlock[0];
byte[] dataBytes = new byte[size];
bits.toBytes(8*dataBytesOffset, dataBytes, 0, size);
byte[] ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]);
blocks.addElement(new BlockPair(dataBytes, ecBytes));
maxNumDataBytes = Math.max(maxNumDataBytes, dataBytes.size());
maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.size());
maxNumDataBytes = Math.max(maxNumDataBytes, size);
maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.length);
dataBytesOffset += numDataBytesInBlock[0];
}
if (numDataBytes != dataBytesOffset) {
@ -398,38 +386,38 @@ public final class Encoder {
// First, place data blocks.
for (int i = 0; i < maxNumDataBytes; ++i) {
for (int j = 0; j < blocks.size(); ++j) {
ByteArray dataBytes = ((BlockPair) blocks.elementAt(j)).getDataBytes();
if (i < dataBytes.size()) {
result.appendBits(dataBytes.at(i), 8);
byte[] dataBytes = ((BlockPair) blocks.elementAt(j)).getDataBytes();
if (i < dataBytes.length) {
result.appendBits(dataBytes[i], 8);
}
}
}
// Then, place error correction blocks.
for (int i = 0; i < maxNumEcBytes; ++i) {
for (int j = 0; j < blocks.size(); ++j) {
ByteArray ecBytes = ((BlockPair) blocks.elementAt(j)).getErrorCorrectionBytes();
if (i < ecBytes.size()) {
result.appendBits(ecBytes.at(i), 8);
byte[] ecBytes = ((BlockPair) blocks.elementAt(j)).getErrorCorrectionBytes();
if (i < ecBytes.length) {
result.appendBits(ecBytes[i], 8);
}
}
}
if (numTotalBytes != result.sizeInBytes()) { // Should be same.
if (numTotalBytes != result.getSizeInBytes()) { // Should be same.
throw new WriterException("Interleaving error: " + numTotalBytes + " and " +
result.sizeInBytes() + " differ.");
result.getSizeInBytes() + " differ.");
}
}
static ByteArray generateECBytes(ByteArray dataBytes, int numEcBytesInBlock) {
int numDataBytes = dataBytes.size();
static byte[] generateECBytes(byte[] dataBytes, int numEcBytesInBlock) {
int numDataBytes = dataBytes.length;
int[] toEncode = new int[numDataBytes + numEcBytesInBlock];
for (int i = 0; i < numDataBytes; i++) {
toEncode[i] = dataBytes.at(i);
toEncode[i] = dataBytes[i] & 0xFF;
}
new ReedSolomonEncoder(GF256.QR_CODE_FIELD).encode(toEncode, numEcBytesInBlock);
ByteArray ecBytes = new ByteArray(numEcBytesInBlock);
byte[] ecBytes = new byte[numEcBytesInBlock];
for (int i = 0; i < numEcBytesInBlock; i++) {
ecBytes.set(i, toEncode[numDataBytes + i]);
ecBytes[i] = (byte) toEncode[numDataBytes + i];
}
return ecBytes;
}
@ -437,7 +425,7 @@ public final class Encoder {
/**
* Append mode info. On success, store the result in "bits".
*/
static void appendModeInfo(Mode mode, BitVector bits) {
static void appendModeInfo(Mode mode, BitArray bits) {
bits.appendBits(mode.getBits(), 4);
}
@ -445,7 +433,7 @@ public final class Encoder {
/**
* Append length info. On success, store the result in "bits".
*/
static void appendLengthInfo(int numLetters, int version, Mode mode, BitVector bits)
static void appendLengthInfo(int numLetters, int version, Mode mode, BitArray bits)
throws WriterException {
int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version));
if (numLetters > ((1 << numBits) - 1)) {
@ -457,7 +445,7 @@ public final class Encoder {
/**
* Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".
*/
static void appendBytes(String content, Mode mode, BitVector bits, String encoding)
static void appendBytes(String content, Mode mode, BitArray bits, String encoding)
throws WriterException {
if (mode.equals(Mode.NUMERIC)) {
appendNumericBytes(content, bits);
@ -472,7 +460,7 @@ public final class Encoder {
}
}
static void appendNumericBytes(String content, BitVector bits) {
static void appendNumericBytes(String content, BitArray bits) {
int length = content.length();
int i = 0;
while (i < length) {
@ -496,7 +484,7 @@ public final class Encoder {
}
}
static void appendAlphanumericBytes(String content, BitVector bits) throws WriterException {
static void appendAlphanumericBytes(String content, BitArray bits) throws WriterException {
int length = content.length();
int i = 0;
while (i < length) {
@ -520,7 +508,7 @@ public final class Encoder {
}
}
static void append8BitBytes(String content, BitVector bits, String encoding)
static void append8BitBytes(String content, BitArray bits, String encoding)
throws WriterException {
byte[] bytes;
try {
@ -533,7 +521,7 @@ public final class Encoder {
}
}
static void appendKanjiBytes(String content, BitVector bits) throws WriterException {
static void appendKanjiBytes(String content, BitArray bits) throws WriterException {
byte[] bytes;
try {
bytes = content.getBytes("Shift_JIS");
@ -559,7 +547,7 @@ public final class Encoder {
}
}
private static void appendECI(CharacterSetECI eci, BitVector bits) {
private static void appendECI(CharacterSetECI eci, BitArray bits) {
bits.appendBits(Mode.ECI.getBits(), 4);
// This is correct for values up to 127, which is all we need now.
bits.appendBits(eci.getValue(), 8);

View file

@ -16,8 +16,6 @@
package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteMatrix;
/**
* @author satorux@google.com (Satoru Takabayashi) - creator
* @author dswitkin@google.com (Daniel Switkin) - ported from C++

View file

@ -17,7 +17,7 @@
package com.google.zxing.qrcode.encoder;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitArray;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
/**
@ -136,7 +136,7 @@ public final class MatrixUtil {
// Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On
// success, store the result in "matrix" and return true.
public static void buildMatrix(BitVector dataBits, ErrorCorrectionLevel ecLevel, int version,
public static void buildMatrix(BitArray dataBits, ErrorCorrectionLevel ecLevel, int version,
int maskPattern, ByteMatrix matrix) throws WriterException {
clearMatrix(matrix);
embedBasicPatterns(version, matrix);
@ -169,13 +169,13 @@ public final class MatrixUtil {
// Embed type information. On success, modify the matrix.
public static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix)
throws WriterException {
BitVector typeInfoBits = new BitVector();
BitArray typeInfoBits = new BitArray();
makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits);
for (int i = 0; i < typeInfoBits.size(); ++i) {
for (int i = 0; i < typeInfoBits.getSize(); ++i) {
// Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
// "typeInfoBits".
int bit = typeInfoBits.at(typeInfoBits.size() - 1 - i);
boolean bit = typeInfoBits.get(typeInfoBits.getSize() - 1 - i);
// Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).
int x1 = TYPE_INFO_COORDINATES[i][0];
@ -202,14 +202,14 @@ public final class MatrixUtil {
if (version < 7) { // Version info is necessary if version >= 7.
return; // Don't need version info.
}
BitVector versionInfoBits = new BitVector();
BitArray versionInfoBits = new BitArray();
makeVersionInfoBits(version, versionInfoBits);
int bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0.
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 3; ++j) {
// Place bits in LSB (least significant bit) to MSB order.
int bit = versionInfoBits.at(bitIndex);
boolean bit = versionInfoBits.get(bitIndex);
bitIndex--;
// Left bottom corner.
matrix.set(i, matrix.getHeight() - 11 + j, bit);
@ -222,7 +222,7 @@ public final class MatrixUtil {
// Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true.
// For debugging purposes, it skips masking process if "getMaskPattern" is -1.
// See 8.7 of JISX0510:2004 (p.38) for how to embed data bits.
public static void embedDataBits(BitVector dataBits, int maskPattern, ByteMatrix matrix)
public static void embedDataBits(BitArray dataBits, int maskPattern, ByteMatrix matrix)
throws WriterException {
int bitIndex = 0;
int direction = -1;
@ -241,20 +241,20 @@ public final class MatrixUtil {
if (!isEmpty(matrix.get(xx, y))) {
continue;
}
int bit;
if (bitIndex < dataBits.size()) {
bit = dataBits.at(bitIndex);
boolean bit;
if (bitIndex < dataBits.getSize()) {
bit = dataBits.get(bitIndex);
++bitIndex;
} else {
// Padding bit. If there is no bit left, we'll fill the left cells with 0, as described
// in 8.4.9 of JISX0510:2004 (p. 24).
bit = 0;
bit = false;
}
// Skip masking if mask_pattern is -1.
if (maskPattern != -1) {
if (MaskUtil.getDataMaskBit(maskPattern, xx, y)) {
bit ^= 0x1;
bit = !bit;
}
}
matrix.set(xx, y, bit);
@ -266,8 +266,8 @@ public final class MatrixUtil {
x -= 2; // Move to the left.
}
// All bits should be consumed.
if (bitIndex != dataBits.size()) {
throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.size());
if (bitIndex != dataBits.getSize()) {
throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.getSize());
}
}
@ -326,7 +326,7 @@ public final class MatrixUtil {
// Make bit vector of type information. On success, store the result in "bits" and return true.
// Encode error correction level and mask pattern. See 8.9 of
// JISX0510:2004 (p.45) for details.
public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitVector bits)
public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitArray bits)
throws WriterException {
if (!QRCode.isValidMaskPattern(maskPattern)) {
throw new WriterException("Invalid mask pattern");
@ -337,24 +337,24 @@ public final class MatrixUtil {
int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY);
bits.appendBits(bchCode, 10);
BitVector maskBits = new BitVector();
BitArray maskBits = new BitArray();
maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15);
bits.xor(maskBits);
if (bits.size() != 15) { // Just in case.
throw new WriterException("should not happen but we got: " + bits.size());
if (bits.getSize() != 15) { // Just in case.
throw new WriterException("should not happen but we got: " + bits.getSize());
}
}
// Make bit vector of version information. On success, store the result in "bits" and return true.
// See 8.10 of JISX0510:2004 (p.45) for details.
public static void makeVersionInfoBits(int version, BitVector bits) throws WriterException {
public static void makeVersionInfoBits(int version, BitArray bits) throws WriterException {
bits.appendBits(version, 6);
int bchCode = calculateBCHCode(version, VERSION_INFO_POLY);
bits.appendBits(bchCode, 12);
if (bits.size() != 18) { // Just in case.
throw new WriterException("should not happen but we got: " + bits.size());
if (bits.getSize() != 18) { // Just in case.
throw new WriterException("should not happen but we got: " + bits.getSize());
}
}

View file

@ -16,7 +16,6 @@
package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.decoder.Mode;

View file

@ -26,7 +26,7 @@ public final class BitMatrixTestCase extends TestCase {
public void testGetSet() {
BitMatrix matrix = new BitMatrix(33);
assertEquals(33, matrix.getDimension());
assertEquals(33, matrix.getHeight());
for (int y = 0; y < 33; y++) {
for (int x = 0; x < 33; x++) {
if (y * x % 3 == 0) {
@ -94,7 +94,7 @@ public final class BitMatrixTestCase extends TestCase {
public void testGetRow() {
BitMatrix matrix = new BitMatrix(102, 5);
for (int x = 0; x < 102; x++) {
if ((x & 3) == 0) {
if ((x & 0x03) == 0) {
matrix.set(x, 2);
}
}
@ -114,7 +114,7 @@ public final class BitMatrixTestCase extends TestCase {
assertEquals(200, array3.getSize());
for (int x = 0; x < 102; x++) {
boolean on = ((x & 3) == 0);
boolean on = ((x & 0x03) == 0);
assertEquals(on, array.get(x));
assertEquals(on, array2.get(x));
assertEquals(on, array3.get(x));

View file

@ -18,7 +18,7 @@ package com.google.zxing.oned;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
import junit.framework.TestCase;
/**
@ -28,12 +28,9 @@ public final class EAN13WriterTestCase extends TestCase {
public void testEncode() throws WriterException {
String testStr = "00010100010110100111011001100100110111101001110101010110011011011001000010101110010011101000100101000";
ByteMatrix result = new EAN13Writer().encode("5901234123457", BarcodeFormat.EAN_13, testStr.length(), 0);
byte[] row = result.getArray()[0];
BitMatrix result = new EAN13Writer().encode("5901234123457", BarcodeFormat.EAN_13, testStr.length(), 0);
for (int i = 0; i < testStr.length(); i++) {
assertEquals("Element " + i, (Integer.parseInt(testStr.substring(i,
i + 1)) == 1) ? 0 : (byte) 255, row[i]);
assertEquals("Element " + i, testStr.charAt(i) == '1', result.get(i, 0));
}
}

View file

@ -18,7 +18,7 @@ package com.google.zxing.oned;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
import junit.framework.TestCase;
/**
@ -28,18 +28,11 @@ public final class EAN8WriterTestCase extends TestCase {
public void testEncode() throws WriterException {
String testStr = "0001010001011010111101111010110111010101001110111001010001001011100101000";
ByteMatrix result = new EAN8Writer().encode("96385074", BarcodeFormat.EAN_8, testStr.length(), 0);
byte[] row = result.getArray()[0];
/*
for (int i = 0; i < row.length; i++) {
System.out.print(row[i] + 1);
}
System.out.println();
*/
BitMatrix result = new EAN8Writer().encode("96385074", BarcodeFormat.EAN_8, testStr.length(), 0);
for (int i = 0; i < testStr.length(); i++) {
assertEquals("Element " + i, (Integer.parseInt(testStr.substring(i,
i + 1)) == 1) ? 0 : (byte) 255, row[i]);
assertEquals("Element " + i,
testStr.charAt(i) == '1',
result.get(i, 0));
}
}

View file

@ -19,7 +19,7 @@ package com.google.zxing.qrcode;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import junit.framework.TestCase;
@ -53,20 +53,22 @@ public final class QRCodeWriterTestCase extends TestCase {
}
// In case the golden images are not monochromatic, convert the RGB values to greyscale.
private static ByteMatrix createMatrixFromImage(BufferedImage image) {
private static BitMatrix createMatrixFromImage(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
int[] pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width);
ByteMatrix matrix = new ByteMatrix(width, height);
BitMatrix matrix = new BitMatrix(width, height);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = pixels[y * width + x];
int luminance = (306 * ((pixel >> 16) & 0xFF) +
601 * ((pixel >> 8) & 0xFF) +
117 * (pixel & 0xFF)) >> 10;
matrix.set(x, y, luminance);
if (luminance <= 0x7F) {
matrix.set(x, y);
}
}
}
return matrix;
@ -76,7 +78,7 @@ public final class QRCodeWriterTestCase extends TestCase {
// The QR should be multiplied up to fit, with extra padding if necessary
int bigEnough = 256;
QRCodeWriter writer = new QRCodeWriter();
ByteMatrix matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, bigEnough,
BitMatrix matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, bigEnough,
bigEnough, null);
assertNotNull(matrix);
assertEquals(bigEnough, matrix.getWidth());
@ -105,21 +107,18 @@ public final class QRCodeWriterTestCase extends TestCase {
BufferedImage image = loadImage(fileName);
assertNotNull(image);
ByteMatrix goldenResult = createMatrixFromImage(image);
BitMatrix goldenResult = createMatrixFromImage(image);
assertNotNull(goldenResult);
QRCodeWriter writer = new QRCodeWriter();
Hashtable<EncodeHintType,Object> hints = new Hashtable<EncodeHintType,Object>();
hints.put(EncodeHintType.ERROR_CORRECTION, ecLevel);
ByteMatrix generatedResult = writer.encode(contents, BarcodeFormat.QR_CODE, resolution,
BitMatrix generatedResult = writer.encode(contents, BarcodeFormat.QR_CODE, resolution,
resolution, hints);
assertEquals("Width should be " + resolution + ", but was " + generatedResult.getWidth(),
resolution, generatedResult.getWidth());
assertEquals("Height should be " + resolution + ", but was " + generatedResult.getHeight(),
resolution, generatedResult.getHeight());
assertTrue("Expected " + goldenResult.toString() + " but got " + generatedResult.toString(),
Arrays.deepEquals(goldenResult.getArray(), generatedResult.getArray()));
assertEquals(resolution, generatedResult.getWidth());
assertEquals(resolution, generatedResult.getHeight());
assertEquals(goldenResult, generatedResult);
}
// Golden images are generated with "qrcode_sample.cc". The images are checked with both eye balls

View file

@ -16,6 +16,7 @@
package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.BitArray;
import junit.framework.TestCase;
/**
@ -24,154 +25,154 @@ import junit.framework.TestCase;
*/
public class BitVectorTestCase extends TestCase {
private static int getUnsignedByte(BitVector v, int index) {
return v.getArray()[index] & 0xff;
private static long getUnsignedInt(BitArray v, int index) {
long result = 0L;
for (int i = 0, offset = index << 3; i < 32; i++) {
if (v.get(offset + i)) {
result |= 1L << (31 - i);
}
}
return result;
}
public void testAppendBit() {
BitVector v = new BitVector();
assertEquals(0, v.sizeInBytes());
BitArray v = new BitArray();
assertEquals(0, v.getSizeInBytes());
// 1
v.appendBit(1);
assertEquals(1, v.size());
assertEquals(0x80, getUnsignedByte(v, 0));
v.appendBit(true);
assertEquals(1, v.getSize());
assertEquals(0x80000000L, getUnsignedInt(v, 0));
// 10
v.appendBit(0);
assertEquals(2, v.size());
assertEquals(0x80, getUnsignedByte(v, 0));
v.appendBit(false);
assertEquals(2, v.getSize());
assertEquals(0x80000000L, getUnsignedInt(v, 0));
// 101
v.appendBit(1);
assertEquals(3, v.size());
assertEquals(0xa0, getUnsignedByte(v, 0));
v.appendBit(true);
assertEquals(3, v.getSize());
assertEquals(0xa0000000L, getUnsignedInt(v, 0));
// 1010
v.appendBit(0);
assertEquals(4, v.size());
assertEquals(0xa0, getUnsignedByte(v, 0));
v.appendBit(false);
assertEquals(4, v.getSize());
assertEquals(0xa0000000L, getUnsignedInt(v, 0));
// 10101
v.appendBit(1);
assertEquals(5, v.size());
assertEquals(0xa8, getUnsignedByte(v, 0));
v.appendBit(true);
assertEquals(5, v.getSize());
assertEquals(0xa8000000L, getUnsignedInt(v, 0));
// 101010
v.appendBit(0);
assertEquals(6, v.size());
assertEquals(0xa8, getUnsignedByte(v, 0));
v.appendBit(false);
assertEquals(6, v.getSize());
assertEquals(0xa8000000L, getUnsignedInt(v, 0));
// 1010101
v.appendBit(1);
assertEquals(7, v.size());
assertEquals(0xaa, getUnsignedByte(v, 0));
v.appendBit(true);
assertEquals(7, v.getSize());
assertEquals(0xaa000000L, getUnsignedInt(v, 0));
// 10101010
v.appendBit(0);
assertEquals(8, v.size());
assertEquals(0xaa, getUnsignedByte(v, 0));
v.appendBit(false);
assertEquals(8, v.getSize());
assertEquals(0xaa000000L, getUnsignedInt(v, 0));
// 10101010 1
v.appendBit(1);
assertEquals(9, v.size());
assertEquals(0xaa, getUnsignedByte(v, 0));
assertEquals(0x80, getUnsignedByte(v, 1));
v.appendBit(true);
assertEquals(9, v.getSize());
assertEquals(0xaa800000L, getUnsignedInt(v, 0));
// 10101010 10
v.appendBit(0);
assertEquals(10, v.size());
assertEquals(0xaa, getUnsignedByte(v, 0));
assertEquals(0x80, getUnsignedByte(v, 1));
v.appendBit(false);
assertEquals(10, v.getSize());
assertEquals(0xaa800000L, getUnsignedInt(v, 0));
}
public void testAppendBits() {
{
BitVector v = new BitVector();
BitArray v = new BitArray();
v.appendBits(0x1, 1);
assertEquals(1, v.size());
assertEquals(0x80, getUnsignedByte(v, 0));
assertEquals(1, v.getSize());
assertEquals(0x80000000L, getUnsignedInt(v, 0));
}
{
BitVector v = new BitVector();
BitArray v = new BitArray();
v.appendBits(0xff, 8);
assertEquals(8, v.size());
assertEquals(0xff, getUnsignedByte(v, 0));
assertEquals(8, v.getSize());
assertEquals(0xff000000L, getUnsignedInt(v, 0));
}
{
BitVector v = new BitVector();
BitArray v = new BitArray();
v.appendBits(0xff7, 12);
assertEquals(12, v.size());
assertEquals(0xff, getUnsignedByte(v, 0));
assertEquals(0x70, getUnsignedByte(v, 1));
assertEquals(12, v.getSize());
assertEquals(0xff700000L, getUnsignedInt(v, 0));
}
}
public void testNumBytes() {
BitVector v = new BitVector();
assertEquals(0, v.sizeInBytes());
v.appendBit(0);
BitArray v = new BitArray();
assertEquals(0, v.getSizeInBytes());
v.appendBit(false);
// 1 bit was added in the vector, so 1 byte should be consumed.
assertEquals(1, v.sizeInBytes());
assertEquals(1, v.getSizeInBytes());
v.appendBits(0, 7);
assertEquals(1, v.sizeInBytes());
assertEquals(1, v.getSizeInBytes());
v.appendBits(0, 8);
assertEquals(2, v.sizeInBytes());
assertEquals(2, v.getSizeInBytes());
v.appendBits(0, 1);
// We now have 17 bits, so 3 bytes should be consumed.
assertEquals(3, v.sizeInBytes());
assertEquals(3, v.getSizeInBytes());
}
public void testAppendBitVector() {
BitVector v1 = new BitVector();
BitArray v1 = new BitArray();
v1.appendBits(0xbe, 8);
BitVector v2 = new BitVector();
BitArray v2 = new BitArray();
v2.appendBits(0xef, 8);
v1.appendBitVector(v2);
v1.appendBitArray(v2);
// beef = 1011 1110 1110 1111
assertEquals("1011111011101111", v1.toString());
assertEquals(" X.XXXXX. XXX.XXXX", v1.toString());
}
public void testXOR() {
{
BitVector v1 = new BitVector();
BitArray v1 = new BitArray();
v1.appendBits(0x5555aaaa, 32);
BitVector v2 = new BitVector();
BitArray v2 = new BitArray();
v2.appendBits(0xaaaa5555, 32);
v1.xor(v2);
assertEquals(0xff, getUnsignedByte(v1, 0));
assertEquals(0xff, getUnsignedByte(v1, 1));
assertEquals(0xff, getUnsignedByte(v1, 2));
assertEquals(0xff, getUnsignedByte(v1, 3));
assertEquals(0xffffffffL, getUnsignedInt(v1, 0));
}
{
BitVector v1 = new BitVector();
BitArray v1 = new BitArray();
v1.appendBits(0x2a, 7); // 010 1010
BitVector v2 = new BitVector();
BitArray v2 = new BitArray();
v2.appendBits(0x55, 7); // 101 0101
v1.xor(v2);
assertEquals(0xfe, getUnsignedByte(v1, 0)); // 1111 1110
assertEquals(0xfe000000L, getUnsignedInt(v1, 0)); // 1111 1110
}
}
public void testAt() {
BitVector v = new BitVector();
BitArray v = new BitArray();
v.appendBits(0xdead, 16); // 1101 1110 1010 1101
assertEquals(1, v.at(0));
assertEquals(1, v.at(1));
assertEquals(0, v.at(2));
assertEquals(1, v.at(3));
assertTrue(v.get(0));
assertTrue(v.get(1));
assertFalse(v.get(2));
assertTrue(v.get(3));
assertEquals(1, v.at(4));
assertEquals(1, v.at(5));
assertEquals(1, v.at(6));
assertEquals(0, v.at(7));
assertTrue(v.get(4));
assertTrue(v.get(5));
assertTrue(v.get(6));
assertFalse(v.get(7));
assertEquals(1, v.at(8));
assertEquals(0, v.at(9));
assertEquals(1, v.at(10));
assertEquals(0, v.at(11));
assertTrue(v.get(8));
assertFalse(v.get(9));
assertTrue(v.get(10));
assertFalse(v.get(11));
assertEquals(1, v.at(12));
assertEquals(1, v.at(13));
assertEquals(0, v.at(14));
assertEquals(1, v.at(15));
assertTrue(v.get(12));
assertTrue(v.get(13));
assertFalse(v.get(14));
assertTrue(v.get(15));
}
public void testToString() {
BitVector v = new BitVector();
BitArray v = new BitArray();
v.appendBits(0xdead, 16); // 1101 1110 1010 1101
assertEquals("1101111010101101", v.toString());
assertEquals(" XX.XXXX. X.X.XX.X", v.toString());
}
}

View file

@ -17,7 +17,7 @@
package com.google.zxing.qrcode.encoder;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteArray;
import com.google.zxing.common.BitArray;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.decoder.Mode;
import junit.framework.TestCase;
@ -60,28 +60,29 @@ public final class EncoderTestCase extends TestCase {
public void testChooseMode() throws WriterException {
// Numeric mode.
assertEquals(Mode.NUMERIC, Encoder.chooseMode("0"));
assertEquals(Mode.NUMERIC, Encoder.chooseMode("0123456789"));
assertSame(Mode.NUMERIC, Encoder.chooseMode("0"));
assertSame(Mode.NUMERIC, Encoder.chooseMode("0123456789"));
// Alphanumeric mode.
assertEquals(Mode.ALPHANUMERIC, Encoder.chooseMode("A"));
assertEquals(Mode.ALPHANUMERIC,
assertSame(Mode.ALPHANUMERIC, Encoder.chooseMode("A"));
assertSame(Mode.ALPHANUMERIC,
Encoder.chooseMode("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"));
// 8-bit byte mode.
assertEquals(Mode.BYTE, Encoder.chooseMode("a"));
assertEquals(Mode.BYTE, Encoder.chooseMode("#"));
assertEquals(Mode.BYTE, Encoder.chooseMode(""));
assertSame(Mode.BYTE, Encoder.chooseMode("a"));
assertSame(Mode.BYTE, Encoder.chooseMode("#"));
assertSame(Mode.BYTE, Encoder.chooseMode(""));
// Kanji mode. We used to use MODE_KANJI for these, but we stopped
// doing that as we cannot distinguish Shift_JIS from other encodings
// from data bytes alone. See also comments in qrcode_encoder.h.
// AIUE in Hiragana in Shift_JIS
assertEquals(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[] {0x8,0xa,0x8,0xa,0x8,0xa,0x8,(byte)0xa6})));
assertSame(Mode.BYTE,
Encoder.chooseMode(shiftJISString(new byte[]{0x8, 0xa, 0x8, 0xa, 0x8, 0xa, 0x8, (byte) 0xa6})));
// Nihon in Kanji in Shift_JIS.
assertEquals(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[] {0x9,0xf,0x9,0x7b})));
assertSame(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[]{0x9, 0xf, 0x9, 0x7b})));
// Sou-Utsu-Byou in Kanji in Shift_JIS.
assertEquals(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[] {0xe,0x4,0x9,0x5,0x9,0x61})));
assertSame(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[]{0xe, 0x4, 0x9, 0x5, 0x9, 0x61})));
}
public void testEncode() throws WriterException {
@ -126,43 +127,43 @@ public final class EncoderTestCase extends TestCase {
}
public void testAppendModeInfo() {
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendModeInfo(Mode.NUMERIC, bits);
assertEquals("0001", bits.toString());
assertEquals(" ...X", bits.toString());
}
public void testAppendLengthInfo() throws WriterException {
{
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendLengthInfo(1, // 1 letter (1/1).
1, // version 1.
Mode.NUMERIC,
bits);
assertEquals("0000000001", bits.toString()); // 10 bits.
assertEquals(" ........ .X", bits.toString()); // 10 bits.
}
{
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendLengthInfo(2, // 2 letters (2/1).
10, // version 10.
Mode.ALPHANUMERIC,
bits);
assertEquals("00000000010", bits.toString()); // 11 bits.
assertEquals(" ........ .X.", bits.toString()); // 11 bits.
}
{
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendLengthInfo(255, // 255 letter (255/1).
27, // version 27.
Mode.BYTE,
bits);
assertEquals("0000000011111111", bits.toString()); // 16 bits.
assertEquals(" ........ XXXXXXXX", bits.toString()); // 16 bits.
}
{
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendLengthInfo(512, // 512 letters (1024/2).
40, // version 40.
Mode.KANJI,
bits);
assertEquals("001000000000", bits.toString()); // 12 bits.
assertEquals(" ..X..... ....", bits.toString()); // 12 bits.
}
}
@ -170,16 +171,16 @@ public final class EncoderTestCase extends TestCase {
{
// Should use appendNumericBytes.
// 1 = 01 = 0001 in 4 bits.
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendBytes("1", Mode.NUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals("0001" , bits.toString());
assertEquals(" ...X" , bits.toString());
}
{
// Should use appendAlphanumericBytes.
// A = 10 = 0xa = 001010 in 6 bits
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendBytes("A", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals("001010" , bits.toString());
assertEquals(" ..X.X." , bits.toString());
// Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
try {
Encoder.appendBytes("a", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
@ -190,60 +191,60 @@ public final class EncoderTestCase extends TestCase {
{
// Should use append8BitBytes.
// 0x61, 0x62, 0x63
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendBytes("abc", Mode.BYTE, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals("011000010110001001100011", bits.toString());
assertEquals(" .XX....X .XX...X. .XX...XX", bits.toString());
// Anything can be encoded in QRCode.MODE_8BIT_BYTE.
Encoder.appendBytes("\0", Mode.BYTE, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
}
{
// Should use appendKanjiBytes.
// 0x93, 0x5f
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), Mode.KANJI, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals("0110110011111", bits.toString());
assertEquals(" .XX.XX.. XXXXX", bits.toString());
}
}
public void testTerminateBits() throws WriterException {
{
BitVector v = new BitVector();
BitArray v = new BitArray();
Encoder.terminateBits(0, v);
assertEquals("", v.toString());
}
{
BitVector v = new BitVector();
BitArray v = new BitArray();
Encoder.terminateBits(1, v);
assertEquals("00000000", v.toString());
assertEquals(" ........", v.toString());
}
{
BitVector v = new BitVector();
BitArray v = new BitArray();
v.appendBits(0, 3); // Append 000
Encoder.terminateBits(1, v);
assertEquals("00000000", v.toString());
assertEquals(" ........", v.toString());
}
{
BitVector v = new BitVector();
BitArray v = new BitArray();
v.appendBits(0, 5); // Append 00000
Encoder.terminateBits(1, v);
assertEquals("00000000", v.toString());
assertEquals(" ........", v.toString());
}
{
BitVector v = new BitVector();
BitArray v = new BitArray();
v.appendBits(0, 8); // Append 00000000
Encoder.terminateBits(1, v);
assertEquals("00000000", v.toString());
assertEquals(" ........", v.toString());
}
{
BitVector v = new BitVector();
BitArray v = new BitArray();
Encoder.terminateBits(2, v);
assertEquals("0000000011101100", v.toString());
assertEquals(" ........ XXX.XX..", v.toString());
}
{
BitVector v = new BitVector();
BitArray v = new BitArray();
v.appendBits(0, 1); // Append 0
Encoder.terminateBits(3, v);
assertEquals("000000001110110000010001", v.toString());
assertEquals(" ........ XXX.XX.. ...X...X", v.toString());
}
}
@ -286,11 +287,11 @@ public final class EncoderTestCase extends TestCase {
public void testInterleaveWithECBytes() throws WriterException {
{
byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
BitVector in = new BitVector();
BitArray in = new BitArray();
for (byte dataByte: dataBytes) {
in.appendBits(dataByte, 8);
}
BitVector out = new BitVector();
BitArray out = new BitArray();
Encoder.interleaveWithECBytes(in, 26, 9, 1, out);
byte[] expected = {
// Data bytes.
@ -299,8 +300,9 @@ public final class EncoderTestCase extends TestCase {
42, (byte)159, 74, (byte)221, (byte)244, (byte)169, (byte)239, (byte)150, (byte)138, 70,
(byte)237, 85, (byte)224, 96, 74, (byte)219, 61,
};
assertEquals(expected.length, out.sizeInBytes());
byte[] outArray = out.getArray();
assertEquals(expected.length, out.getSizeInBytes());
byte[] outArray = new byte[expected.length];
out.toBytes(0, outArray, 0, expected.length);
// Can't use Arrays.equals(), because outArray may be longer than out.sizeInBytes()
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], outArray[x]);
@ -316,11 +318,11 @@ public final class EncoderTestCase extends TestCase {
(byte)135, (byte)151, (byte)160, (byte)236, 17, (byte)236, 17, (byte)236, 17, (byte)236,
17
};
BitVector in = new BitVector();
BitArray in = new BitArray();
for (byte dataByte: dataBytes) {
in.appendBits(dataByte, 8);
}
BitVector out = new BitVector();
BitArray out = new BitArray();
Encoder.interleaveWithECBytes(in, 134, 62, 4, out);
byte[] expected = {
// Data bytes.
@ -339,8 +341,9 @@ public final class EncoderTestCase extends TestCase {
(byte)140, 61, (byte)179, (byte)154, (byte)214, (byte)138, (byte)147, 87, 27, 96, 77, 47,
(byte)187, 49, (byte)156, (byte)214,
};
assertEquals(expected.length, out.sizeInBytes());
byte[] outArray = out.getArray();
assertEquals(expected.length, out.getSizeInBytes());
byte[] outArray = new byte[expected.length];
out.toBytes(0, outArray, 0, expected.length);
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], outArray[x]);
}
@ -350,31 +353,31 @@ public final class EncoderTestCase extends TestCase {
public void testAppendNumericBytes() {
{
// 1 = 01 = 0001 in 4 bits.
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendNumericBytes("1", bits);
assertEquals("0001" , bits.toString());
assertEquals(" ...X" , bits.toString());
}
{
// 12 = 0xc = 0001100 in 7 bits.
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendNumericBytes("12", bits);
assertEquals("0001100" , bits.toString());
assertEquals(" ...XX.." , bits.toString());
}
{
// 123 = 0x7b = 0001111011 in 10 bits.
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendNumericBytes("123", bits);
assertEquals("0001111011" , bits.toString());
assertEquals(" ...XXXX. XX" , bits.toString());
}
{
// 1234 = "123" + "4" = 0001111011 + 0100
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendNumericBytes("1234", bits);
assertEquals("0001111011" + "0100" , bits.toString());
assertEquals(" ...XXXX. XX.X.." , bits.toString());
}
{
// Empty.
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendNumericBytes("", bits);
assertEquals("" , bits.toString());
}
@ -383,31 +386,31 @@ public final class EncoderTestCase extends TestCase {
public void testAppendAlphanumericBytes() throws WriterException {
{
// A = 10 = 0xa = 001010 in 6 bits
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendAlphanumericBytes("A", bits);
assertEquals("001010" , bits.toString());
assertEquals(" ..X.X." , bits.toString());
}
{
// AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendAlphanumericBytes("AB", bits);
assertEquals("00111001101", bits.toString());
assertEquals(" ..XXX..X X.X", bits.toString());
}
{
// ABC = "AB" + "C" = 00111001101 + 001100
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendAlphanumericBytes("ABC", bits);
assertEquals("00111001101" + "001100" , bits.toString());
assertEquals(" ..XXX..X X.X..XX. ." , bits.toString());
}
{
// Empty.
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendAlphanumericBytes("", bits);
assertEquals("" , bits.toString());
}
{
// Invalid data.
BitVector bits = new BitVector();
BitArray bits = new BitArray();
try {
Encoder.appendAlphanumericBytes("abc", bits);
} catch (WriterException we) {
@ -419,13 +422,13 @@ public final class EncoderTestCase extends TestCase {
public void testAppend8BitBytes() throws WriterException {
{
// 0x61, 0x62, 0x63
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.append8BitBytes("abc", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals("01100001" + "01100010" + "01100011", bits.toString());
assertEquals(" .XX....X .XX...X. .XX...XX", bits.toString());
}
{
// Empty.
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.append8BitBytes("", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals("", bits.toString());
}
@ -433,11 +436,11 @@ public final class EncoderTestCase extends TestCase {
// Numbers are from page 21 of JISX0510:2004
public void testAppendKanjiBytes() throws WriterException {
BitVector bits = new BitVector();
BitArray bits = new BitArray();
Encoder.appendKanjiBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), bits);
assertEquals("0110110011111", bits.toString());
assertEquals(" .XX.XX.. XXXXX", bits.toString());
Encoder.appendKanjiBytes(shiftJISString(new byte[] {(byte)0xe4,(byte)0xaa}), bits);
assertEquals("0110110011111" + "1101010101010", bits.toString());
assertEquals(" .XX.XX.. XXXXXXX. X.X.X.X. X.", bits.toString());
}
// Numbers are from http://www.swetake.com/qr/qr3.html and
@ -445,37 +448,37 @@ public final class EncoderTestCase extends TestCase {
public void testGenerateECBytes() {
{
byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
ByteArray ecBytes = Encoder.generateECBytes(new ByteArray(dataBytes), 17);
byte[] ecBytes = Encoder.generateECBytes(dataBytes, 17);
int[] expected = {
42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61
};
assertEquals(expected.length, ecBytes.size());
assertEquals(expected.length, ecBytes.length);
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], ecBytes.at(x));
assertEquals(expected[x], ecBytes[x] & 0xFF);
}
}
{
byte[] dataBytes = {67, 70, 22, 38, 54, 70, 86, 102, 118,
(byte)134, (byte)150, (byte)166, (byte)182, (byte)198, (byte)214};
ByteArray ecBytes = Encoder.generateECBytes(new ByteArray(dataBytes), 18);
byte[] ecBytes = Encoder.generateECBytes(dataBytes, 18);
int[] expected = {
175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187
};
assertEquals(expected.length, ecBytes.size());
assertEquals(expected.length, ecBytes.length);
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], ecBytes.at(x));
assertEquals(expected[x], ecBytes[x] & 0xFF);
}
}
{
// High-order zero cofficient case.
// High-order zero coefficient case.
byte[] dataBytes = {32, 49, (byte)205, 69, 42, 20, 0, (byte)236, 17};
ByteArray ecBytes = Encoder.generateECBytes(new ByteArray(dataBytes), 17);
byte[] ecBytes = Encoder.generateECBytes(dataBytes, 17);
int[] expected = {
0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213
};
assertEquals(expected.length, ecBytes.size());
assertEquals(expected.length, ecBytes.length);
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], ecBytes.at(x));
assertEquals(expected[x], ecBytes[x] & 0xFF);
}
}
}

View file

@ -16,7 +16,6 @@
package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteMatrix;
import junit.framework.TestCase;
/**

View file

@ -17,7 +17,7 @@
package com.google.zxing.qrcode.encoder;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.BitArray;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import junit.framework.TestCase;
@ -202,7 +202,7 @@ public final class MatrixUtilTestCase extends TestCase {
" 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
BitVector bits = new BitVector();
BitArray bits = new BitArray();
ByteMatrix matrix = new ByteMatrix(21, 21);
MatrixUtil.clearMatrix(matrix);
MatrixUtil.embedBasicPatterns(1, matrix);
@ -237,7 +237,7 @@ public final class MatrixUtilTestCase extends TestCase {
char[] bytes = {32, 65, 205, 69, 41, 220, 46, 128, 236,
42, 159, 74, 221, 244, 169, 239, 150, 138,
70, 237, 85, 224, 96, 74, 219 , 61};
BitVector bits = new BitVector();
BitArray bits = new BitArray();
for (char c: bytes) {
bits.appendBits(c, 8);
}
@ -280,18 +280,18 @@ public final class MatrixUtilTestCase extends TestCase {
// tested them in TEST(calculateBCHCode).
public void testMakeVersionInfoBits() throws WriterException {
// From Appendix D in JISX0510:2004 (p 68)
BitVector bits = new BitVector();
BitArray bits = new BitArray();
MatrixUtil.makeVersionInfoBits(7, bits);
assertEquals("000111110010010100", bits.toString());
assertEquals(" ...XXXXX ..X..X.X ..", 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() throws WriterException {
// From Appendix C in JISX0510:2004 (p 65)
BitVector bits = new BitVector();
BitArray bits = new BitArray();
MatrixUtil.makeTypeInfoBits(ErrorCorrectionLevel.M,
5, bits);
assertEquals("100000011001110", bits.toString());
assertEquals(" X......X X..XXX.", bits.toString());
}
}

View file

@ -16,7 +16,6 @@
package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.decoder.Mode;
import junit.framework.TestCase;

View file

@ -17,7 +17,6 @@
package com.google.zxing.client.j2se;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.ByteMatrix;
import javax.imageio.ImageIO;
import java.io.File;
@ -26,7 +25,7 @@ import java.io.IOException;
import java.awt.image.BufferedImage;
/**
* Writes a {@link BitMatrix} or {@link ByteMatrix} to {@link BufferedImage},
* Writes a {@link BitMatrix} to {@link BufferedImage},
* file or stream. Provided here instead of core since it depends on
* Java SE libraries.
*
@ -55,25 +54,6 @@ public final class MatrixToImageWriter {
return image;
}
/**
* Renders a {@link ByteMatrix} as an image, as a
* {@link BufferedImage}. The byte values are construed as (unsigned)
* luminance values, in theory.
* However, anything but 0 will be rendered as white, and 0 will be
* rendered as black.
*/
public static BufferedImage toBufferedImage(ByteMatrix matrix) {
int width = matrix.getWidth();
int height = matrix.getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, matrix.get(x, y) == 0 ? BLACK : WHITE);
}
}
return image;
}
/**
* Writes a {@link BitMatrix} to a file.
*
@ -85,17 +65,6 @@ public final class MatrixToImageWriter {
ImageIO.write(image, format, file);
}
/**
* Writes a {@link ByteMatrix} to a file.
*
* @see #toBufferedImage(ByteMatrix)
*/
public static void writeToFile(ByteMatrix matrix, String format, File file)
throws IOException {
BufferedImage image = toBufferedImage(matrix);
ImageIO.write(image, format, file);
}
/**
* Writes a {@link BitMatrix} to a stream.
*
@ -107,15 +76,4 @@ public final class MatrixToImageWriter {
ImageIO.write(image, format, stream);
}
/**
* Writes a {@link ByteMatrix} to a stream.
*
* @see #toBufferedImage(ByteMatrix)
*/
public static void writeToStream(ByteMatrix matrix, String format, OutputStream stream)
throws IOException {
BufferedImage image = toBufferedImage(matrix);
ImageIO.write(image, format, stream);
}
}