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

View file

@ -16,7 +16,7 @@
package com.google.zxing; 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.Code128Writer;
import com.google.zxing.oned.Code39Writer; import com.google.zxing.oned.Code39Writer;
import com.google.zxing.oned.EAN13Writer; import com.google.zxing.oned.EAN13Writer;
@ -34,13 +34,13 @@ import java.util.Hashtable;
*/ */
public final class MultiFormatWriter implements Writer { 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 { int height) throws WriterException {
return encode(contents, format, width, height, null); 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 { Hashtable hints) throws WriterException {
Writer writer; Writer writer;

View file

@ -16,7 +16,7 @@
package com.google.zxing; package com.google.zxing;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.BitMatrix;
import java.util.Hashtable; import java.util.Hashtable;
@ -36,7 +36,7 @@ public interface Writer {
* @param height The preferred height in pixels * @param height The preferred height in pixels
* @return The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white) * @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; throws WriterException;
/** /**
@ -48,7 +48,7 @@ public interface Writer {
* @param hints Additional parameters to supply to the encoder * @param hints Additional parameters to supply to the encoder
* @return The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white) * @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; 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 // resulting binary at runtime on Android. If we find a solution to this, these should be changed
// back to private. // back to private.
public int[] bits; public int[] bits;
public final int size; public int size;
public BitArray() {
this.size = 0;
this.bits = new int[1];
}
public BitArray(int size) { public BitArray(int size) {
if (size < 1) {
throw new IllegalArgumentException("size must be at least 1");
}
this.size = size; this.size = size;
this.bits = makeArray(size); this.bits = makeArray(size);
} }
@ -42,6 +44,18 @@ public final class BitArray {
return size; 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 * @param i bit to get
* @return true iff bit i is set * @return true iff bit i is set
@ -130,6 +144,69 @@ public final class BitArray {
return true; 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 * @return underlying array of ints. The first element holds the first 32 bits, and the least
* significant bit is bit 0. * significant bit is bit 0.
@ -153,11 +230,7 @@ public final class BitArray {
} }
private static int[] makeArray(int size) { private static int[] makeArray(int size) {
int arraySize = size >> 5; return new int[(size + 31) >> 5];
if ((size & 0x1F) != 0) {
arraySize++;
}
return new int[arraySize];
} }
public String toString() { public String toString() {

View file

@ -50,11 +50,7 @@ public final class BitMatrix {
} }
this.width = width; this.width = width;
this.height = height; this.height = height;
int rowSize = width >> 5; this.rowSize = (width + 31) >> 5;
if ((width & 0x1f) != 0) {
rowSize++;
}
this.rowSize = rowSize;
bits = new int[rowSize * height]; bits = new int[rowSize * height];
} }
@ -163,17 +159,32 @@ public final class BitMatrix {
return height; return height;
} }
/** public boolean equals(Object o) {
* This method is for compatibility with older code. It's only logical to call if the matrix if (!(o instanceof BitMatrix)) {
* is square, so I'm throwing if that's not the case. return false;
*
* @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");
} }
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() { 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 * @throws FormatException if dimension is < 10 or > 144 or not 0 mod 2
*/ */
BitMatrixParser(BitMatrix bitMatrix) throws FormatException { BitMatrixParser(BitMatrix bitMatrix) throws FormatException {
int dimension = bitMatrix.getDimension(); int dimension = bitMatrix.getHeight();
if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0) { if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0) {
throw FormatException.getFormatInstance(); throw FormatException.getFormatInstance();
} }
@ -41,7 +41,7 @@ final class BitMatrixParser {
version = readVersion(bitMatrix); version = readVersion(bitMatrix);
this.mappingBitMatrix = extractDataRegion(bitMatrix); this.mappingBitMatrix = extractDataRegion(bitMatrix);
// TODO(bbrown): Make this work for rectangular symbols // 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. // TODO(bbrown): make this work for rectangular dimensions as well.
int numRows = bitMatrix.getDimension(); int numRows = bitMatrix.getHeight();
int numColumns = numRows; int numColumns = numRows;
return Version.getVersionForDimensions(numRows, numColumns); return Version.getVersionForDimensions(numRows, numColumns);
@ -84,7 +84,7 @@ final class BitMatrixParser {
int row = 4; int row = 4;
int column = 0; int column = 0;
// TODO(bbrown): Data Matrix can be rectangular, assuming square for now // TODO(bbrown): Data Matrix can be rectangular, assuming square for now
int numRows = mappingBitMatrix.getDimension(); int numRows = mappingBitMatrix.getHeight();
int numColumns = numRows; int numColumns = numRows;
boolean corner1Read = false; boolean corner1Read = false;
@ -408,7 +408,7 @@ final class BitMatrixParser {
int symbolSizeColumns = version.getSymbolSizeColumns(); int symbolSizeColumns = version.getSymbolSizeColumns();
// TODO(bbrown): Make this work with rectangular codes // 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"); 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 java.util.Hashtable;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException; 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}. * 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 final class Code128Writer extends UPCEANWriter {
public ByteMatrix encode(String contents, public BitMatrix encode(String contents,
BarcodeFormat format, BarcodeFormat format,
int width, int width,
int height, int height,

View file

@ -19,7 +19,7 @@ package com.google.zxing.oned;
import java.util.Hashtable; import java.util.Hashtable;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException; 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}. * 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 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 { Hashtable hints) throws WriterException {
if (format != BarcodeFormat.CODE_39) { if (format != BarcodeFormat.CODE_39) {
throw new IllegalArgumentException("Can only encode CODE_39, but got " + format); 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.BarcodeFormat;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.BitMatrix;
import java.util.Hashtable; import java.util.Hashtable;
/** /**
* This object renders an EAN13 code as a ByteMatrix 2D array of greyscale * This object renders an EAN13 code as a {@link BitMatrix}.
* values.
* *
* @author aripollak@gmail.com (Ari Pollak) * @author aripollak@gmail.com (Ari Pollak)
*/ */
@ -37,7 +36,7 @@ public final class EAN13Writer extends UPCEANWriter {
(7 * 6) + // right bars (7 * 6) + // right bars
3; // end guard 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 { Hashtable hints) throws WriterException {
if (format != BarcodeFormat.EAN_13) { if (format != BarcodeFormat.EAN_13) {
throw new IllegalArgumentException("Can only encode EAN_13, but got " + format); 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.BarcodeFormat;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.BitMatrix;
import java.util.Hashtable; import java.util.Hashtable;
/** /**
* This object renders an EAN8 code as a ByteMatrix 2D array of greyscale * This object renders an EAN8 code as a {@link BitMatrix}.
* values.
* *
* @author aripollak@gmail.com (Ari Pollak) * @author aripollak@gmail.com (Ari Pollak)
*/ */
@ -36,7 +35,7 @@ public final class EAN8Writer extends UPCEANWriter {
(7 * 4) + // right bars (7 * 4) + // right bars
3; // end guard 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 { Hashtable hints) throws WriterException {
if (format != BarcodeFormat.EAN_8) { if (format != BarcodeFormat.EAN_8) {
throw new IllegalArgumentException("Can only encode EAN_8, but got " 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 java.util.Hashtable;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException; 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}. * 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 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 { Hashtable hints) throws WriterException {
if (format != BarcodeFormat.ITF) { if (format != BarcodeFormat.ITF) {
throw new IllegalArgumentException("Can only encode ITF, but got " + format); 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.BarcodeFormat;
import com.google.zxing.Writer; import com.google.zxing.Writer;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.BitMatrix;
import java.util.Hashtable; import java.util.Hashtable;
@ -31,12 +31,12 @@ import java.util.Hashtable;
*/ */
public abstract class UPCEANWriter implements Writer { 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 { throws WriterException {
return encode(contents, format, width, height, null); 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 { Hashtable hints) throws WriterException {
if (contents == null || contents.length() == 0) { if (contents == null || contents.length() == 0) {
throw new IllegalArgumentException("Found empty contents"); 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) */ /** @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; int inputWidth = code.length;
// Add quiet zone on both sides // Add quiet zone on both sides
int fullWidth = inputWidth + (UPCEANReader.START_END_PATTERN.length << 1); int fullWidth = inputWidth + (UPCEANReader.START_END_PATTERN.length << 1);
@ -62,37 +62,12 @@ public abstract class UPCEANWriter implements Writer {
int multiple = outputWidth / fullWidth; int multiple = outputWidth / fullWidth;
int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
ByteMatrix output = new ByteMatrix(outputWidth, outputHeight); BitMatrix output = new BitMatrix(outputWidth, outputHeight);
byte[][] outputArray = output.getArray(); for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
if (code[inputX] == 1) {
byte[] row = new byte[outputWidth]; output.setRegion(outputX, 0, multiple, outputHeight);
// 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 = (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; return output;
} }

View file

@ -60,7 +60,7 @@ final class BitMatrixParser {
* @return an array of codewords. * @return an array of codewords.
*/ */
int[] readCodewords() throws FormatException { int[] readCodewords() throws FormatException {
int width = bitMatrix.getDimension(); int width = bitMatrix.getWidth();
// TODO should be a rectangular matrix // TODO should be a rectangular matrix
int height = width; int height = width;
@ -186,7 +186,7 @@ final class BitMatrixParser {
*/ */
int processRow(int[] rowCounters, int rowNumber, int rowHeight, int[] codewords, int next) int processRow(int[] rowCounters, int rowNumber, int rowHeight, int[] codewords, int next)
throws FormatException { throws FormatException {
int width = bitMatrix.getDimension(); int width = bitMatrix.getWidth();
int columnNumber = 0; int columnNumber = 0;
long symbol = 0; long symbol = 0;
for (int i = 0; i < width; i += MODULES_IN_SYMBOL) { 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.EncodeHintType;
import com.google.zxing.Writer; import com.google.zxing.Writer;
import com.google.zxing.WriterException; 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.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.encoder.Encoder; import com.google.zxing.qrcode.encoder.Encoder;
import com.google.zxing.qrcode.encoder.QRCode; import com.google.zxing.qrcode.encoder.QRCode;
@ -28,7 +29,7 @@ import com.google.zxing.qrcode.encoder.QRCode;
import java.util.Hashtable; 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) * @author dswitkin@google.com (Daniel Switkin)
*/ */
@ -36,13 +37,13 @@ public final class QRCodeWriter implements Writer {
private static final int QUIET_ZONE_SIZE = 4; 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 { throws WriterException {
return encode(contents, format, width, height, null); 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 { Hashtable hints) throws WriterException {
if (contents == null || contents.length() == 0) { 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 // 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). // 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(); ByteMatrix input = code.getMatrix();
int inputWidth = input.getWidth(); int inputWidth = input.getWidth();
int inputHeight = input.getHeight(); int inputHeight = input.getHeight();
@ -90,62 +91,18 @@ public final class QRCodeWriter implements Writer {
int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
int topPadding = (outputHeight - (inputHeight * multiple)) / 2; int topPadding = (outputHeight - (inputHeight * multiple)) / 2;
ByteMatrix output = new ByteMatrix(outputWidth, outputHeight); BitMatrix output = new BitMatrix(outputWidth, outputHeight);
byte[][] outputArray = output.getArray();
// We could be tricky and use the first row in each set of multiple as the temporary storage, for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {
// instead of allocating this separate array. // Write the contents of this row of the barcode
byte[] row = new byte[outputWidth]; for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
if (input.get(inputX, inputY) == 1) {
// 1. Write the white lines at the top output.setRegion(outputX, outputY, multiple, multiple);
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);
} }
} }
// 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; 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 * @throws FormatException if dimension is not >= 21 and 1 mod 4
*/ */
BitMatrixParser(BitMatrix bitMatrix) throws FormatException { BitMatrixParser(BitMatrix bitMatrix) throws FormatException {
int dimension = bitMatrix.getDimension(); int dimension = bitMatrix.getHeight();
if (dimension < 21 || (dimension & 0x03) != 1) { if (dimension < 21 || (dimension & 0x03) != 1) {
throw FormatException.getFormatInstance(); throw FormatException.getFormatInstance();
} }
@ -68,7 +68,7 @@ final class BitMatrixParser {
} }
// Read the top-right/bottom-left pattern too // Read the top-right/bottom-left pattern too
int dimension = bitMatrix.getDimension(); int dimension = bitMatrix.getHeight();
int formatInfoBits2 = 0; int formatInfoBits2 = 0;
int iMin = dimension - 8; int iMin = dimension - 8;
for (int i = dimension - 1; i >= iMin; i--) { for (int i = dimension - 1; i >= iMin; i--) {
@ -98,7 +98,7 @@ final class BitMatrixParser {
return parsedVersion; return parsedVersion;
} }
int dimension = bitMatrix.getDimension(); int dimension = bitMatrix.getHeight();
int provisionalVersion = (dimension - 17) >> 2; int provisionalVersion = (dimension - 17) >> 2;
if (provisionalVersion <= 6) { 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 // 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. // some bits from reading as we wind through the bit matrix.
DataMask dataMask = DataMask.forReference((int) formatInfo.getDataMask()); DataMask dataMask = DataMask.forReference((int) formatInfo.getDataMask());
int dimension = bitMatrix.getDimension(); int dimension = bitMatrix.getHeight();
dataMask.unmaskBitMatrix(bitMatrix, dimension); dataMask.unmaskBitMatrix(bitMatrix, dimension);
BitMatrix functionPattern = version.buildFunctionPattern(); 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; package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteArray;
final class BlockPair { final class BlockPair {
private final ByteArray dataBytes; private final byte[] dataBytes;
private final ByteArray errorCorrectionBytes; private final byte[] errorCorrectionBytes;
BlockPair(ByteArray data, ByteArray errorCorrection) { BlockPair(byte[] data, byte[] errorCorrection) {
dataBytes = data; dataBytes = data;
errorCorrectionBytes = errorCorrection; errorCorrectionBytes = errorCorrection;
} }
public ByteArray getDataBytes() { public byte[] getDataBytes() {
return dataBytes; return dataBytes;
} }
public ByteArray getErrorCorrectionBytes() { public byte[] getErrorCorrectionBytes() {
return errorCorrectionBytes; return errorCorrectionBytes;
} }

View file

@ -14,7 +14,7 @@
* limitations under the License. * 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 * 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; 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) { public void clear(byte value) {
for (int y = 0; y < height; ++y) { for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) { 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.EncodeHintType;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.common.ByteArray; import com.google.zxing.common.BitArray;
import com.google.zxing.common.ByteMatrix;
import com.google.zxing.common.CharacterSetECI; import com.google.zxing.common.CharacterSetECI;
import com.google.zxing.common.reedsolomon.GF256; import com.google.zxing.common.reedsolomon.GF256;
import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; import com.google.zxing.common.reedsolomon.ReedSolomonEncoder;
@ -91,14 +90,14 @@ public final class Encoder {
Mode mode = chooseMode(content, encoding); Mode mode = chooseMode(content, encoding);
// Step 2: Append "bytes" into "dataBits" in appropriate encoding. // Step 2: Append "bytes" into "dataBits" in appropriate encoding.
BitVector dataBits = new BitVector(); BitArray dataBits = new BitArray();
appendBytes(content, mode, dataBits, encoding); appendBytes(content, mode, dataBits, encoding);
// Step 3: Initialize QR code that can contain "dataBits". // Step 3: Initialize QR code that can contain "dataBits".
int numInputBytes = dataBits.sizeInBytes(); int numInputBytes = dataBits.getSizeInBytes();
initQRCode(numInputBytes, ecLevel, mode, qrCode); initQRCode(numInputBytes, ecLevel, mode, qrCode);
// Step 4: Build another bit vector that contains header and data. // Step 4: Build another bit vector that contains header and data.
BitVector headerAndDataBits = new BitVector(); BitArray headerAndDataBits = new BitArray();
// Step 4.5: Append ECI message if applicable // Step 4.5: Append ECI message if applicable
if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.equals(encoding)) { if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.equals(encoding)) {
@ -110,15 +109,15 @@ public final class Encoder {
appendModeInfo(mode, headerAndDataBits); 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); appendLengthInfo(numLetters, qrCode.getVersion(), mode, headerAndDataBits);
headerAndDataBits.appendBitVector(dataBits); headerAndDataBits.appendBitArray(dataBits);
// Step 5: Terminate the bits properly. // Step 5: Terminate the bits properly.
terminateBits(qrCode.getNumDataBytes(), headerAndDataBits); terminateBits(qrCode.getNumDataBytes(), headerAndDataBits);
// Step 6: Interleave data bits with error correction code. // Step 6: Interleave data bits with error correction code.
BitVector finalBits = new BitVector(); BitArray finalBits = new BitArray();
interleaveWithECBytes(headerAndDataBits, qrCode.getNumTotalBytes(), qrCode.getNumDataBytes(), interleaveWithECBytes(headerAndDataBits, qrCode.getNumTotalBytes(), qrCode.getNumDataBytes(),
qrCode.getNumRSBlocks(), finalBits); qrCode.getNumRSBlocks(), finalBits);
@ -201,7 +200,7 @@ public final class Encoder {
return true; 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 { ByteMatrix matrix) throws WriterException {
int minPenalty = Integer.MAX_VALUE; // Lower penalty is better. 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). * 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; int capacity = numDataBytes << 3;
if (bits.size() > capacity) { if (bits.getSize() > capacity) {
throw new WriterException("data bits cannot fit in the QR Code" + bits.size() + " > " + throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " +
capacity); 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. // 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. // If the last byte isn't 8-bit aligned, we'll add padding bits.
int numBitsInLastByte = bits.getSize() & 0x07;
if (numBitsInLastByte > 0) { if (numBitsInLastByte > 0) {
int numPaddingBits = 8 - numBitsInLastByte; for (int i = numBitsInLastByte; i < 8; i++) {
for (int i = 0; i < numPaddingBits; ++i) { bits.appendBit(false);
bits.appendBit(0);
} }
} }
// 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). // 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) { for (int i = 0; i < numPaddingBytes; ++i) {
if (i % 2 == 0) { bits.appendBits(((i & 0x01) == 0) ? 0xEC : 0x11, 8);
bits.appendBits(0xec, 8);
} else {
bits.appendBits(0x11, 8);
} }
} if (bits.getSize() != capacity) {
if (bits.size() != capacity) {
throw new WriterException("Bits size does not equal 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 * 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. * "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
*/ */
static void interleaveWithECBytes(BitVector bits, int numTotalBytes, static void interleaveWithECBytes(BitArray bits, int numTotalBytes,
int numDataBytes, int numRSBlocks, BitVector result) throws WriterException { int numDataBytes, int numRSBlocks, BitArray result) throws WriterException {
// "bits" must have "getNumDataBytes" bytes of data. // "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"); throw new WriterException("Number of bits and data bytes does not match");
} }
@ -382,13 +369,14 @@ public final class Encoder {
numTotalBytes, numDataBytes, numRSBlocks, i, numTotalBytes, numDataBytes, numRSBlocks, i,
numDataBytesInBlock, numEcBytesInBlock); numDataBytesInBlock, numEcBytesInBlock);
ByteArray dataBytes = new ByteArray(); int size = numDataBytesInBlock[0];
dataBytes.set(bits.getArray(), dataBytesOffset, numDataBytesInBlock[0]); byte[] dataBytes = new byte[size];
ByteArray ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]); bits.toBytes(8*dataBytesOffset, dataBytes, 0, size);
byte[] ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]);
blocks.addElement(new BlockPair(dataBytes, ecBytes)); blocks.addElement(new BlockPair(dataBytes, ecBytes));
maxNumDataBytes = Math.max(maxNumDataBytes, dataBytes.size()); maxNumDataBytes = Math.max(maxNumDataBytes, size);
maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.size()); maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.length);
dataBytesOffset += numDataBytesInBlock[0]; dataBytesOffset += numDataBytesInBlock[0];
} }
if (numDataBytes != dataBytesOffset) { if (numDataBytes != dataBytesOffset) {
@ -398,38 +386,38 @@ public final class Encoder {
// First, place data blocks. // First, place data blocks.
for (int i = 0; i < maxNumDataBytes; ++i) { for (int i = 0; i < maxNumDataBytes; ++i) {
for (int j = 0; j < blocks.size(); ++j) { for (int j = 0; j < blocks.size(); ++j) {
ByteArray dataBytes = ((BlockPair) blocks.elementAt(j)).getDataBytes(); byte[] dataBytes = ((BlockPair) blocks.elementAt(j)).getDataBytes();
if (i < dataBytes.size()) { if (i < dataBytes.length) {
result.appendBits(dataBytes.at(i), 8); result.appendBits(dataBytes[i], 8);
} }
} }
} }
// Then, place error correction blocks. // Then, place error correction blocks.
for (int i = 0; i < maxNumEcBytes; ++i) { for (int i = 0; i < maxNumEcBytes; ++i) {
for (int j = 0; j < blocks.size(); ++j) { for (int j = 0; j < blocks.size(); ++j) {
ByteArray ecBytes = ((BlockPair) blocks.elementAt(j)).getErrorCorrectionBytes(); byte[] ecBytes = ((BlockPair) blocks.elementAt(j)).getErrorCorrectionBytes();
if (i < ecBytes.size()) { if (i < ecBytes.length) {
result.appendBits(ecBytes.at(i), 8); 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 " + throw new WriterException("Interleaving error: " + numTotalBytes + " and " +
result.sizeInBytes() + " differ."); result.getSizeInBytes() + " differ.");
} }
} }
static ByteArray generateECBytes(ByteArray dataBytes, int numEcBytesInBlock) { static byte[] generateECBytes(byte[] dataBytes, int numEcBytesInBlock) {
int numDataBytes = dataBytes.size(); int numDataBytes = dataBytes.length;
int[] toEncode = new int[numDataBytes + numEcBytesInBlock]; int[] toEncode = new int[numDataBytes + numEcBytesInBlock];
for (int i = 0; i < numDataBytes; i++) { 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); 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++) { for (int i = 0; i < numEcBytesInBlock; i++) {
ecBytes.set(i, toEncode[numDataBytes + i]); ecBytes[i] = (byte) toEncode[numDataBytes + i];
} }
return ecBytes; return ecBytes;
} }
@ -437,7 +425,7 @@ public final class Encoder {
/** /**
* Append mode info. On success, store the result in "bits". * 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); bits.appendBits(mode.getBits(), 4);
} }
@ -445,7 +433,7 @@ public final class Encoder {
/** /**
* Append length info. On success, store the result in "bits". * 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 { throws WriterException {
int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version)); int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version));
if (numLetters > ((1 << numBits) - 1)) { if (numLetters > ((1 << numBits) - 1)) {
@ -457,7 +445,7 @@ public final class Encoder {
/** /**
* Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". * 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 { throws WriterException {
if (mode.equals(Mode.NUMERIC)) { if (mode.equals(Mode.NUMERIC)) {
appendNumericBytes(content, bits); 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 length = content.length();
int i = 0; int i = 0;
while (i < length) { 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 length = content.length();
int i = 0; int i = 0;
while (i < length) { 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 { throws WriterException {
byte[] bytes; byte[] bytes;
try { 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; byte[] bytes;
try { try {
bytes = content.getBytes("Shift_JIS"); 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); bits.appendBits(Mode.ECI.getBits(), 4);
// This is correct for values up to 127, which is all we need now. // This is correct for values up to 127, which is all we need now.
bits.appendBits(eci.getValue(), 8); bits.appendBits(eci.getValue(), 8);

View file

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

View file

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

View file

@ -16,7 +16,6 @@
package com.google.zxing.qrcode.encoder; 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.ErrorCorrectionLevel;
import com.google.zxing.qrcode.decoder.Mode; import com.google.zxing.qrcode.decoder.Mode;

View file

@ -26,7 +26,7 @@ public final class BitMatrixTestCase extends TestCase {
public void testGetSet() { public void testGetSet() {
BitMatrix matrix = new BitMatrix(33); BitMatrix matrix = new BitMatrix(33);
assertEquals(33, matrix.getDimension()); assertEquals(33, matrix.getHeight());
for (int y = 0; y < 33; y++) { for (int y = 0; y < 33; y++) {
for (int x = 0; x < 33; x++) { for (int x = 0; x < 33; x++) {
if (y * x % 3 == 0) { if (y * x % 3 == 0) {
@ -94,7 +94,7 @@ public final class BitMatrixTestCase extends TestCase {
public void testGetRow() { public void testGetRow() {
BitMatrix matrix = new BitMatrix(102, 5); BitMatrix matrix = new BitMatrix(102, 5);
for (int x = 0; x < 102; x++) { for (int x = 0; x < 102; x++) {
if ((x & 3) == 0) { if ((x & 0x03) == 0) {
matrix.set(x, 2); matrix.set(x, 2);
} }
} }
@ -114,7 +114,7 @@ public final class BitMatrixTestCase extends TestCase {
assertEquals(200, array3.getSize()); assertEquals(200, array3.getSize());
for (int x = 0; x < 102; x++) { for (int x = 0; x < 102; x++) {
boolean on = ((x & 3) == 0); boolean on = ((x & 0x03) == 0);
assertEquals(on, array.get(x)); assertEquals(on, array.get(x));
assertEquals(on, array2.get(x)); assertEquals(on, array2.get(x));
assertEquals(on, array3.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.BarcodeFormat;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.BitMatrix;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -28,12 +28,9 @@ public final class EAN13WriterTestCase extends TestCase {
public void testEncode() throws WriterException { public void testEncode() throws WriterException {
String testStr = "00010100010110100111011001100100110111101001110101010110011011011001000010101110010011101000100101000"; String testStr = "00010100010110100111011001100100110111101001110101010110011011011001000010101110010011101000100101000";
ByteMatrix result = new EAN13Writer().encode("5901234123457", BarcodeFormat.EAN_13, testStr.length(), 0); BitMatrix result = new EAN13Writer().encode("5901234123457", BarcodeFormat.EAN_13, testStr.length(), 0);
byte[] row = result.getArray()[0];
for (int i = 0; i < testStr.length(); i++) { for (int i = 0; i < testStr.length(); i++) {
assertEquals("Element " + i, (Integer.parseInt(testStr.substring(i, assertEquals("Element " + i, testStr.charAt(i) == '1', result.get(i, 0));
i + 1)) == 1) ? 0 : (byte) 255, row[i]);
} }
} }

View file

@ -18,7 +18,7 @@ package com.google.zxing.oned;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.BitMatrix;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -28,18 +28,11 @@ public final class EAN8WriterTestCase extends TestCase {
public void testEncode() throws WriterException { public void testEncode() throws WriterException {
String testStr = "0001010001011010111101111010110111010101001110111001010001001011100101000"; String testStr = "0001010001011010111101111010110111010101001110111001010001001011100101000";
ByteMatrix result = new EAN8Writer().encode("96385074", BarcodeFormat.EAN_8, testStr.length(), 0); BitMatrix 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();
*/
for (int i = 0; i < testStr.length(); i++) { for (int i = 0; i < testStr.length(); i++) {
assertEquals("Element " + i, (Integer.parseInt(testStr.substring(i, assertEquals("Element " + i,
i + 1)) == 1) ? 0 : (byte) 255, row[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.BarcodeFormat;
import com.google.zxing.EncodeHintType; import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException; 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 com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import junit.framework.TestCase; 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. // 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 width = image.getWidth();
int height = image.getHeight(); int height = image.getHeight();
int[] pixels = new int[width * height]; int[] pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width); 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 y = 0; y < height; y++) {
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
int pixel = pixels[y * width + x]; int pixel = pixels[y * width + x];
int luminance = (306 * ((pixel >> 16) & 0xFF) + int luminance = (306 * ((pixel >> 16) & 0xFF) +
601 * ((pixel >> 8) & 0xFF) + 601 * ((pixel >> 8) & 0xFF) +
117 * (pixel & 0xFF)) >> 10; 117 * (pixel & 0xFF)) >> 10;
matrix.set(x, y, luminance); if (luminance <= 0x7F) {
matrix.set(x, y);
}
} }
} }
return matrix; 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 // The QR should be multiplied up to fit, with extra padding if necessary
int bigEnough = 256; int bigEnough = 256;
QRCodeWriter writer = new QRCodeWriter(); 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); bigEnough, null);
assertNotNull(matrix); assertNotNull(matrix);
assertEquals(bigEnough, matrix.getWidth()); assertEquals(bigEnough, matrix.getWidth());
@ -105,21 +107,18 @@ public final class QRCodeWriterTestCase extends TestCase {
BufferedImage image = loadImage(fileName); BufferedImage image = loadImage(fileName);
assertNotNull(image); assertNotNull(image);
ByteMatrix goldenResult = createMatrixFromImage(image); BitMatrix goldenResult = createMatrixFromImage(image);
assertNotNull(goldenResult); assertNotNull(goldenResult);
QRCodeWriter writer = new QRCodeWriter(); QRCodeWriter writer = new QRCodeWriter();
Hashtable<EncodeHintType,Object> hints = new Hashtable<EncodeHintType,Object>(); Hashtable<EncodeHintType,Object> hints = new Hashtable<EncodeHintType,Object>();
hints.put(EncodeHintType.ERROR_CORRECTION, ecLevel); 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); resolution, hints);
assertEquals("Width should be " + resolution + ", but was " + generatedResult.getWidth(), assertEquals(resolution, generatedResult.getWidth());
resolution, generatedResult.getWidth()); assertEquals(resolution, generatedResult.getHeight());
assertEquals("Height should be " + resolution + ", but was " + generatedResult.getHeight(), assertEquals(goldenResult, generatedResult);
resolution, generatedResult.getHeight());
assertTrue("Expected " + goldenResult.toString() + " but got " + generatedResult.toString(),
Arrays.deepEquals(goldenResult.getArray(), generatedResult.getArray()));
} }
// Golden images are generated with "qrcode_sample.cc". The images are checked with both eye balls // 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; package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.BitArray;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -24,154 +25,154 @@ import junit.framework.TestCase;
*/ */
public class BitVectorTestCase extends TestCase { public class BitVectorTestCase extends TestCase {
private static int getUnsignedByte(BitVector v, int index) { private static long getUnsignedInt(BitArray v, int index) {
return v.getArray()[index] & 0xff; 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() { public void testAppendBit() {
BitVector v = new BitVector(); BitArray v = new BitArray();
assertEquals(0, v.sizeInBytes()); assertEquals(0, v.getSizeInBytes());
// 1 // 1
v.appendBit(1); v.appendBit(true);
assertEquals(1, v.size()); assertEquals(1, v.getSize());
assertEquals(0x80, getUnsignedByte(v, 0)); assertEquals(0x80000000L, getUnsignedInt(v, 0));
// 10 // 10
v.appendBit(0); v.appendBit(false);
assertEquals(2, v.size()); assertEquals(2, v.getSize());
assertEquals(0x80, getUnsignedByte(v, 0)); assertEquals(0x80000000L, getUnsignedInt(v, 0));
// 101 // 101
v.appendBit(1); v.appendBit(true);
assertEquals(3, v.size()); assertEquals(3, v.getSize());
assertEquals(0xa0, getUnsignedByte(v, 0)); assertEquals(0xa0000000L, getUnsignedInt(v, 0));
// 1010 // 1010
v.appendBit(0); v.appendBit(false);
assertEquals(4, v.size()); assertEquals(4, v.getSize());
assertEquals(0xa0, getUnsignedByte(v, 0)); assertEquals(0xa0000000L, getUnsignedInt(v, 0));
// 10101 // 10101
v.appendBit(1); v.appendBit(true);
assertEquals(5, v.size()); assertEquals(5, v.getSize());
assertEquals(0xa8, getUnsignedByte(v, 0)); assertEquals(0xa8000000L, getUnsignedInt(v, 0));
// 101010 // 101010
v.appendBit(0); v.appendBit(false);
assertEquals(6, v.size()); assertEquals(6, v.getSize());
assertEquals(0xa8, getUnsignedByte(v, 0)); assertEquals(0xa8000000L, getUnsignedInt(v, 0));
// 1010101 // 1010101
v.appendBit(1); v.appendBit(true);
assertEquals(7, v.size()); assertEquals(7, v.getSize());
assertEquals(0xaa, getUnsignedByte(v, 0)); assertEquals(0xaa000000L, getUnsignedInt(v, 0));
// 10101010 // 10101010
v.appendBit(0); v.appendBit(false);
assertEquals(8, v.size()); assertEquals(8, v.getSize());
assertEquals(0xaa, getUnsignedByte(v, 0)); assertEquals(0xaa000000L, getUnsignedInt(v, 0));
// 10101010 1 // 10101010 1
v.appendBit(1); v.appendBit(true);
assertEquals(9, v.size()); assertEquals(9, v.getSize());
assertEquals(0xaa, getUnsignedByte(v, 0)); assertEquals(0xaa800000L, getUnsignedInt(v, 0));
assertEquals(0x80, getUnsignedByte(v, 1));
// 10101010 10 // 10101010 10
v.appendBit(0); v.appendBit(false);
assertEquals(10, v.size()); assertEquals(10, v.getSize());
assertEquals(0xaa, getUnsignedByte(v, 0)); assertEquals(0xaa800000L, getUnsignedInt(v, 0));
assertEquals(0x80, getUnsignedByte(v, 1));
} }
public void testAppendBits() { public void testAppendBits() {
{ {
BitVector v = new BitVector(); BitArray v = new BitArray();
v.appendBits(0x1, 1); v.appendBits(0x1, 1);
assertEquals(1, v.size()); assertEquals(1, v.getSize());
assertEquals(0x80, getUnsignedByte(v, 0)); assertEquals(0x80000000L, getUnsignedInt(v, 0));
} }
{ {
BitVector v = new BitVector(); BitArray v = new BitArray();
v.appendBits(0xff, 8); v.appendBits(0xff, 8);
assertEquals(8, v.size()); assertEquals(8, v.getSize());
assertEquals(0xff, getUnsignedByte(v, 0)); assertEquals(0xff000000L, getUnsignedInt(v, 0));
} }
{ {
BitVector v = new BitVector(); BitArray v = new BitArray();
v.appendBits(0xff7, 12); v.appendBits(0xff7, 12);
assertEquals(12, v.size()); assertEquals(12, v.getSize());
assertEquals(0xff, getUnsignedByte(v, 0)); assertEquals(0xff700000L, getUnsignedInt(v, 0));
assertEquals(0x70, getUnsignedByte(v, 1));
} }
} }
public void testNumBytes() { public void testNumBytes() {
BitVector v = new BitVector(); BitArray v = new BitArray();
assertEquals(0, v.sizeInBytes()); assertEquals(0, v.getSizeInBytes());
v.appendBit(0); v.appendBit(false);
// 1 bit was added in the vector, so 1 byte should be consumed. // 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); v.appendBits(0, 7);
assertEquals(1, v.sizeInBytes()); assertEquals(1, v.getSizeInBytes());
v.appendBits(0, 8); v.appendBits(0, 8);
assertEquals(2, v.sizeInBytes()); assertEquals(2, v.getSizeInBytes());
v.appendBits(0, 1); v.appendBits(0, 1);
// We now have 17 bits, so 3 bytes should be consumed. // We now have 17 bits, so 3 bytes should be consumed.
assertEquals(3, v.sizeInBytes()); assertEquals(3, v.getSizeInBytes());
} }
public void testAppendBitVector() { public void testAppendBitVector() {
BitVector v1 = new BitVector(); BitArray v1 = new BitArray();
v1.appendBits(0xbe, 8); v1.appendBits(0xbe, 8);
BitVector v2 = new BitVector(); BitArray v2 = new BitArray();
v2.appendBits(0xef, 8); v2.appendBits(0xef, 8);
v1.appendBitVector(v2); v1.appendBitArray(v2);
// beef = 1011 1110 1110 1111 // beef = 1011 1110 1110 1111
assertEquals("1011111011101111", v1.toString()); assertEquals(" X.XXXXX. XXX.XXXX", v1.toString());
} }
public void testXOR() { public void testXOR() {
{ {
BitVector v1 = new BitVector(); BitArray v1 = new BitArray();
v1.appendBits(0x5555aaaa, 32); v1.appendBits(0x5555aaaa, 32);
BitVector v2 = new BitVector(); BitArray v2 = new BitArray();
v2.appendBits(0xaaaa5555, 32); v2.appendBits(0xaaaa5555, 32);
v1.xor(v2); v1.xor(v2);
assertEquals(0xff, getUnsignedByte(v1, 0)); assertEquals(0xffffffffL, getUnsignedInt(v1, 0));
assertEquals(0xff, getUnsignedByte(v1, 1));
assertEquals(0xff, getUnsignedByte(v1, 2));
assertEquals(0xff, getUnsignedByte(v1, 3));
} }
{ {
BitVector v1 = new BitVector(); BitArray v1 = new BitArray();
v1.appendBits(0x2a, 7); // 010 1010 v1.appendBits(0x2a, 7); // 010 1010
BitVector v2 = new BitVector(); BitArray v2 = new BitArray();
v2.appendBits(0x55, 7); // 101 0101 v2.appendBits(0x55, 7); // 101 0101
v1.xor(v2); v1.xor(v2);
assertEquals(0xfe, getUnsignedByte(v1, 0)); // 1111 1110 assertEquals(0xfe000000L, getUnsignedInt(v1, 0)); // 1111 1110
} }
} }
public void testAt() { public void testAt() {
BitVector v = new BitVector(); BitArray v = new BitArray();
v.appendBits(0xdead, 16); // 1101 1110 1010 1101 v.appendBits(0xdead, 16); // 1101 1110 1010 1101
assertEquals(1, v.at(0)); assertTrue(v.get(0));
assertEquals(1, v.at(1)); assertTrue(v.get(1));
assertEquals(0, v.at(2)); assertFalse(v.get(2));
assertEquals(1, v.at(3)); assertTrue(v.get(3));
assertEquals(1, v.at(4)); assertTrue(v.get(4));
assertEquals(1, v.at(5)); assertTrue(v.get(5));
assertEquals(1, v.at(6)); assertTrue(v.get(6));
assertEquals(0, v.at(7)); assertFalse(v.get(7));
assertEquals(1, v.at(8)); assertTrue(v.get(8));
assertEquals(0, v.at(9)); assertFalse(v.get(9));
assertEquals(1, v.at(10)); assertTrue(v.get(10));
assertEquals(0, v.at(11)); assertFalse(v.get(11));
assertEquals(1, v.at(12)); assertTrue(v.get(12));
assertEquals(1, v.at(13)); assertTrue(v.get(13));
assertEquals(0, v.at(14)); assertFalse(v.get(14));
assertEquals(1, v.at(15)); assertTrue(v.get(15));
} }
public void testToString() { public void testToString() {
BitVector v = new BitVector(); BitArray v = new BitArray();
v.appendBits(0xdead, 16); // 1101 1110 1010 1101 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; package com.google.zxing.qrcode.encoder;
import com.google.zxing.WriterException; 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.ErrorCorrectionLevel;
import com.google.zxing.qrcode.decoder.Mode; import com.google.zxing.qrcode.decoder.Mode;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -60,28 +60,29 @@ public final class EncoderTestCase extends TestCase {
public void testChooseMode() throws WriterException { public void testChooseMode() throws WriterException {
// Numeric mode. // Numeric mode.
assertEquals(Mode.NUMERIC, Encoder.chooseMode("0")); assertSame(Mode.NUMERIC, Encoder.chooseMode("0"));
assertEquals(Mode.NUMERIC, Encoder.chooseMode("0123456789")); assertSame(Mode.NUMERIC, Encoder.chooseMode("0123456789"));
// Alphanumeric mode. // Alphanumeric mode.
assertEquals(Mode.ALPHANUMERIC, Encoder.chooseMode("A")); assertSame(Mode.ALPHANUMERIC, Encoder.chooseMode("A"));
assertEquals(Mode.ALPHANUMERIC, assertSame(Mode.ALPHANUMERIC,
Encoder.chooseMode("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")); Encoder.chooseMode("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"));
// 8-bit byte mode. // 8-bit byte mode.
assertEquals(Mode.BYTE, Encoder.chooseMode("a")); assertSame(Mode.BYTE, Encoder.chooseMode("a"));
assertEquals(Mode.BYTE, Encoder.chooseMode("#")); assertSame(Mode.BYTE, Encoder.chooseMode("#"));
assertEquals(Mode.BYTE, Encoder.chooseMode("")); assertSame(Mode.BYTE, Encoder.chooseMode(""));
// Kanji mode. We used to use MODE_KANJI for these, but we stopped // Kanji mode. We used to use MODE_KANJI for these, but we stopped
// doing that as we cannot distinguish Shift_JIS from other encodings // doing that as we cannot distinguish Shift_JIS from other encodings
// from data bytes alone. See also comments in qrcode_encoder.h. // from data bytes alone. See also comments in qrcode_encoder.h.
// AIUE in Hiragana in Shift_JIS // 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. // 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. // 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 { public void testEncode() throws WriterException {
@ -126,43 +127,43 @@ public final class EncoderTestCase extends TestCase {
} }
public void testAppendModeInfo() { public void testAppendModeInfo() {
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendModeInfo(Mode.NUMERIC, bits); Encoder.appendModeInfo(Mode.NUMERIC, bits);
assertEquals("0001", bits.toString()); assertEquals(" ...X", bits.toString());
} }
public void testAppendLengthInfo() throws WriterException { public void testAppendLengthInfo() throws WriterException {
{ {
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendLengthInfo(1, // 1 letter (1/1). Encoder.appendLengthInfo(1, // 1 letter (1/1).
1, // version 1. 1, // version 1.
Mode.NUMERIC, Mode.NUMERIC,
bits); 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). Encoder.appendLengthInfo(2, // 2 letters (2/1).
10, // version 10. 10, // version 10.
Mode.ALPHANUMERIC, Mode.ALPHANUMERIC,
bits); 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). Encoder.appendLengthInfo(255, // 255 letter (255/1).
27, // version 27. 27, // version 27.
Mode.BYTE, Mode.BYTE,
bits); 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). Encoder.appendLengthInfo(512, // 512 letters (1024/2).
40, // version 40. 40, // version 40.
Mode.KANJI, Mode.KANJI,
bits); 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. // Should use appendNumericBytes.
// 1 = 01 = 0001 in 4 bits. // 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); Encoder.appendBytes("1", Mode.NUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals("0001" , bits.toString()); assertEquals(" ...X" , bits.toString());
} }
{ {
// Should use appendAlphanumericBytes. // Should use appendAlphanumericBytes.
// A = 10 = 0xa = 001010 in 6 bits // A = 10 = 0xa = 001010 in 6 bits
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendBytes("A", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); 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. // Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
try { try {
Encoder.appendBytes("a", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); Encoder.appendBytes("a", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
@ -190,60 +191,60 @@ public final class EncoderTestCase extends TestCase {
{ {
// Should use append8BitBytes. // Should use append8BitBytes.
// 0x61, 0x62, 0x63 // 0x61, 0x62, 0x63
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendBytes("abc", Mode.BYTE, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); 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. // Anything can be encoded in QRCode.MODE_8BIT_BYTE.
Encoder.appendBytes("\0", Mode.BYTE, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); Encoder.appendBytes("\0", Mode.BYTE, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
} }
{ {
// Should use appendKanjiBytes. // Should use appendKanjiBytes.
// 0x93, 0x5f // 0x93, 0x5f
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), Mode.KANJI, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); 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 { public void testTerminateBits() throws WriterException {
{ {
BitVector v = new BitVector(); BitArray v = new BitArray();
Encoder.terminateBits(0, v); Encoder.terminateBits(0, v);
assertEquals("", v.toString()); assertEquals("", v.toString());
} }
{ {
BitVector v = new BitVector(); BitArray v = new BitArray();
Encoder.terminateBits(1, v); 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 v.appendBits(0, 3); // Append 000
Encoder.terminateBits(1, v); 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 v.appendBits(0, 5); // Append 00000
Encoder.terminateBits(1, v); 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 v.appendBits(0, 8); // Append 00000000
Encoder.terminateBits(1, v); Encoder.terminateBits(1, v);
assertEquals("00000000", v.toString()); assertEquals(" ........", v.toString());
} }
{ {
BitVector v = new BitVector(); BitArray v = new BitArray();
Encoder.terminateBits(2, v); 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 v.appendBits(0, 1); // Append 0
Encoder.terminateBits(3, v); 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 { public void testInterleaveWithECBytes() throws WriterException {
{ {
byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236}; 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) { for (byte dataByte: dataBytes) {
in.appendBits(dataByte, 8); in.appendBits(dataByte, 8);
} }
BitVector out = new BitVector(); BitArray out = new BitArray();
Encoder.interleaveWithECBytes(in, 26, 9, 1, out); Encoder.interleaveWithECBytes(in, 26, 9, 1, out);
byte[] expected = { byte[] expected = {
// Data bytes. // 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, 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, (byte)237, 85, (byte)224, 96, 74, (byte)219, 61,
}; };
assertEquals(expected.length, out.sizeInBytes()); assertEquals(expected.length, out.getSizeInBytes());
byte[] outArray = out.getArray(); 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() // Can't use Arrays.equals(), because outArray may be longer than out.sizeInBytes()
for (int x = 0; x < expected.length; x++) { for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], outArray[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, (byte)135, (byte)151, (byte)160, (byte)236, 17, (byte)236, 17, (byte)236, 17, (byte)236,
17 17
}; };
BitVector in = new BitVector(); BitArray in = new BitArray();
for (byte dataByte: dataBytes) { for (byte dataByte: dataBytes) {
in.appendBits(dataByte, 8); in.appendBits(dataByte, 8);
} }
BitVector out = new BitVector(); BitArray out = new BitArray();
Encoder.interleaveWithECBytes(in, 134, 62, 4, out); Encoder.interleaveWithECBytes(in, 134, 62, 4, out);
byte[] expected = { byte[] expected = {
// Data bytes. // 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)140, 61, (byte)179, (byte)154, (byte)214, (byte)138, (byte)147, 87, 27, 96, 77, 47,
(byte)187, 49, (byte)156, (byte)214, (byte)187, 49, (byte)156, (byte)214,
}; };
assertEquals(expected.length, out.sizeInBytes()); assertEquals(expected.length, out.getSizeInBytes());
byte[] outArray = out.getArray(); byte[] outArray = new byte[expected.length];
out.toBytes(0, outArray, 0, expected.length);
for (int x = 0; x < expected.length; x++) { for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], outArray[x]); assertEquals(expected[x], outArray[x]);
} }
@ -350,31 +353,31 @@ public final class EncoderTestCase extends TestCase {
public void testAppendNumericBytes() { public void testAppendNumericBytes() {
{ {
// 1 = 01 = 0001 in 4 bits. // 1 = 01 = 0001 in 4 bits.
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendNumericBytes("1", bits); Encoder.appendNumericBytes("1", bits);
assertEquals("0001" , bits.toString()); assertEquals(" ...X" , bits.toString());
} }
{ {
// 12 = 0xc = 0001100 in 7 bits. // 12 = 0xc = 0001100 in 7 bits.
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendNumericBytes("12", bits); Encoder.appendNumericBytes("12", bits);
assertEquals("0001100" , bits.toString()); assertEquals(" ...XX.." , bits.toString());
} }
{ {
// 123 = 0x7b = 0001111011 in 10 bits. // 123 = 0x7b = 0001111011 in 10 bits.
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendNumericBytes("123", bits); Encoder.appendNumericBytes("123", bits);
assertEquals("0001111011" , bits.toString()); assertEquals(" ...XXXX. XX" , bits.toString());
} }
{ {
// 1234 = "123" + "4" = 0001111011 + 0100 // 1234 = "123" + "4" = 0001111011 + 0100
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendNumericBytes("1234", bits); Encoder.appendNumericBytes("1234", bits);
assertEquals("0001111011" + "0100" , bits.toString()); assertEquals(" ...XXXX. XX.X.." , bits.toString());
} }
{ {
// Empty. // Empty.
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendNumericBytes("", bits); Encoder.appendNumericBytes("", bits);
assertEquals("" , bits.toString()); assertEquals("" , bits.toString());
} }
@ -383,31 +386,31 @@ public final class EncoderTestCase extends TestCase {
public void testAppendAlphanumericBytes() throws WriterException { public void testAppendAlphanumericBytes() throws WriterException {
{ {
// A = 10 = 0xa = 001010 in 6 bits // A = 10 = 0xa = 001010 in 6 bits
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendAlphanumericBytes("A", bits); Encoder.appendAlphanumericBytes("A", bits);
assertEquals("001010" , bits.toString()); assertEquals(" ..X.X." , bits.toString());
} }
{ {
// AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits // AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendAlphanumericBytes("AB", bits); Encoder.appendAlphanumericBytes("AB", bits);
assertEquals("00111001101", bits.toString()); assertEquals(" ..XXX..X X.X", bits.toString());
} }
{ {
// ABC = "AB" + "C" = 00111001101 + 001100 // ABC = "AB" + "C" = 00111001101 + 001100
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendAlphanumericBytes("ABC", bits); Encoder.appendAlphanumericBytes("ABC", bits);
assertEquals("00111001101" + "001100" , bits.toString()); assertEquals(" ..XXX..X X.X..XX. ." , bits.toString());
} }
{ {
// Empty. // Empty.
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendAlphanumericBytes("", bits); Encoder.appendAlphanumericBytes("", bits);
assertEquals("" , bits.toString()); assertEquals("" , bits.toString());
} }
{ {
// Invalid data. // Invalid data.
BitVector bits = new BitVector(); BitArray bits = new BitArray();
try { try {
Encoder.appendAlphanumericBytes("abc", bits); Encoder.appendAlphanumericBytes("abc", bits);
} catch (WriterException we) { } catch (WriterException we) {
@ -419,13 +422,13 @@ public final class EncoderTestCase extends TestCase {
public void testAppend8BitBytes() throws WriterException { public void testAppend8BitBytes() throws WriterException {
{ {
// 0x61, 0x62, 0x63 // 0x61, 0x62, 0x63
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.append8BitBytes("abc", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); 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. // Empty.
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.append8BitBytes("", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING); Encoder.append8BitBytes("", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals("", bits.toString()); assertEquals("", bits.toString());
} }
@ -433,11 +436,11 @@ public final class EncoderTestCase extends TestCase {
// Numbers are from page 21 of JISX0510:2004 // Numbers are from page 21 of JISX0510:2004
public void testAppendKanjiBytes() throws WriterException { public void testAppendKanjiBytes() throws WriterException {
BitVector bits = new BitVector(); BitArray bits = new BitArray();
Encoder.appendKanjiBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), bits); 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); 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 // Numbers are from http://www.swetake.com/qr/qr3.html and
@ -445,37 +448,37 @@ public final class EncoderTestCase extends TestCase {
public void testGenerateECBytes() { public void testGenerateECBytes() {
{ {
byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236}; 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 = { int[] expected = {
42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61 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++) { 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[] dataBytes = {67, 70, 22, 38, 54, 70, 86, 102, 118,
(byte)134, (byte)150, (byte)166, (byte)182, (byte)198, (byte)214}; (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 = { int[] expected = {
175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187 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++) { 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}; 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 = { int[] expected = {
0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213 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++) { 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; package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteMatrix;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**

View file

@ -17,7 +17,7 @@
package com.google.zxing.qrcode.encoder; package com.google.zxing.qrcode.encoder;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.BitArray;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import junit.framework.TestCase; 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 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 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"; " 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); ByteMatrix matrix = new ByteMatrix(21, 21);
MatrixUtil.clearMatrix(matrix); MatrixUtil.clearMatrix(matrix);
MatrixUtil.embedBasicPatterns(1, 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, char[] bytes = {32, 65, 205, 69, 41, 220, 46, 128, 236,
42, 159, 74, 221, 244, 169, 239, 150, 138, 42, 159, 74, 221, 244, 169, 239, 150, 138,
70, 237, 85, 224, 96, 74, 219 , 61}; 70, 237, 85, 224, 96, 74, 219 , 61};
BitVector bits = new BitVector(); BitArray bits = new BitArray();
for (char c: bytes) { for (char c: bytes) {
bits.appendBits(c, 8); bits.appendBits(c, 8);
} }
@ -280,18 +280,18 @@ public final class MatrixUtilTestCase extends TestCase {
// tested them in TEST(calculateBCHCode). // tested them in TEST(calculateBCHCode).
public void testMakeVersionInfoBits() throws WriterException { public void testMakeVersionInfoBits() throws WriterException {
// From Appendix D in JISX0510:2004 (p 68) // From Appendix D in JISX0510:2004 (p 68)
BitVector bits = new BitVector(); BitArray bits = new BitArray();
MatrixUtil.makeVersionInfoBits(7, bits); 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 // We don't test a lot of cases in this function since we've already
// tested them in TEST(calculateBCHCode). // tested them in TEST(calculateBCHCode).
public void testMakeTypeInfoInfoBits() throws WriterException { public void testMakeTypeInfoInfoBits() throws WriterException {
// From Appendix C in JISX0510:2004 (p 65) // From Appendix C in JISX0510:2004 (p 65)
BitVector bits = new BitVector(); BitArray bits = new BitArray();
MatrixUtil.makeTypeInfoBits(ErrorCorrectionLevel.M, MatrixUtil.makeTypeInfoBits(ErrorCorrectionLevel.M,
5, bits); 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; 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.ErrorCorrectionLevel;
import com.google.zxing.qrcode.decoder.Mode; import com.google.zxing.qrcode.decoder.Mode;
import junit.framework.TestCase; import junit.framework.TestCase;

View file

@ -17,7 +17,6 @@
package com.google.zxing.client.j2se; package com.google.zxing.client.j2se;
import com.google.zxing.common.BitMatrix; import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.ByteMatrix;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.io.File; import java.io.File;
@ -26,7 +25,7 @@ import java.io.IOException;
import java.awt.image.BufferedImage; 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 * file or stream. Provided here instead of core since it depends on
* Java SE libraries. * Java SE libraries.
* *
@ -55,25 +54,6 @@ public final class MatrixToImageWriter {
return image; 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. * Writes a {@link BitMatrix} to a file.
* *
@ -85,17 +65,6 @@ public final class MatrixToImageWriter {
ImageIO.write(image, format, file); 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. * Writes a {@link BitMatrix} to a stream.
* *
@ -107,15 +76,4 @@ public final class MatrixToImageWriter {
ImageIO.write(image, format, stream); 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);
}
} }