Issue 198

git-svn-id: https://zxing.googlecode.com/svn/trunk@972 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2009-06-19 13:23:09 +00:00
parent 9f509172b6
commit 63a1dc62a3
15 changed files with 478 additions and 22 deletions

View file

@ -84,16 +84,24 @@ public final class Intents {
/** /**
* The data to encode. Use Intent.putExtra(DATA, data) where data is either a String or a * The data to encode. Use Intent.putExtra(DATA, data) where data is either a String or a
* Bundle, depending on the type specified. See Contents for details. * Bundle, depending on the type and format specified. Non-QR Code formats should
* just use a String here. For QR Code, see Contents for details.
*/ */
public static final String DATA = "ENCODE_DATA"; public static final String DATA = "ENCODE_DATA";
/** /**
* The type of data being supplied. Use Intent.putExtra(TYPE, type) with one of * The type of data being supplied if the format is QR Code. Use
* Contents.Type. * Intent.putExtra(TYPE, type) with one of Contents.Type.
*/ */
public static final String TYPE = "ENCODE_TYPE"; public static final String TYPE = "ENCODE_TYPE";
/**
* The barcode format to be displayed. If this isn't specified or is blank,
* it defaults to QR Code. Use Intent.putExtra(FORMAT, format), where
* format is one of Contents.Format.
*/
public static final String FORMAT = "com.google.zxing.client.android.ENCODE_FORMAT";
private Encode() { private Encode() {
} }
} }

View file

@ -36,6 +36,7 @@ public final class QRCodeEncoder {
private String mContents; private String mContents;
private String mDisplayContents; private String mDisplayContents;
private String mTitle; private String mTitle;
private BarcodeFormat mFormat;
public QRCodeEncoder(Activity activity, Intent intent) { public QRCodeEncoder(Activity activity, Intent intent) {
mActivity = activity; mActivity = activity;
@ -45,7 +46,8 @@ public final class QRCodeEncoder {
} }
public void requestBarcode(Handler handler, int pixelResolution) { public void requestBarcode(Handler handler, int pixelResolution) {
Thread encodeThread = new EncodeThread(mContents, handler, pixelResolution); Thread encodeThread = new EncodeThread(mContents, handler, pixelResolution,
mFormat);
encodeThread.start(); encodeThread.start();
} }
@ -61,17 +63,51 @@ public final class QRCodeEncoder {
return mTitle; return mTitle;
} }
// It would be nice if the string encoding lived in the core ZXing library, but we use platform public String getFormat() {
// specific code like PhoneNumberUtils, so it can't. return mFormat.toString();
}
// It would be nice if the string encoding lived in the core ZXing library,
// but we use platform specific code like PhoneNumberUtils, so it can't.
private boolean encodeContents(Intent intent) { private boolean encodeContents(Intent intent) {
if (intent == null) { if (intent == null) {
return false; return false;
} }
// default to QR_CODE if no format given
String format = intent.getStringExtra(Intents.Encode.FORMAT);
if (format == null || format.length() == 0 ||
format.equals(Contents.Format.QR_CODE)) {
String type = intent.getStringExtra(Intents.Encode.TYPE); String type = intent.getStringExtra(Intents.Encode.TYPE);
if (type == null || type.length() == 0) { if (type == null || type.length() == 0) {
return false; return false;
} }
mFormat = BarcodeFormat.QR_CODE;
encodeQRCodeContents(intent, type);
} else {
String data = intent.getStringExtra(Intents.Encode.DATA);
if (data != null && data.length() != 0) {
mContents = data;
mDisplayContents = data;
mTitle = mActivity.getString(R.string.contents_text);
if (format.equals(Contents.Format.CODE_128))
mFormat = BarcodeFormat.CODE_128;
else if (format.equals(Contents.Format.CODE_39))
mFormat = BarcodeFormat.CODE_39;
else if (format.equals(Contents.Format.EAN_8))
mFormat = BarcodeFormat.EAN_8;
else if (format.equals(Contents.Format.EAN_13))
mFormat = BarcodeFormat.EAN_13;
else if (format.equals(Contents.Format.UPC_A))
mFormat = BarcodeFormat.UPC_A;
else if (format.equals(Contents.Format.UPC_E))
mFormat = BarcodeFormat.UPC_E;
}
}
return mContents != null && mContents.length() > 0;
}
private void encodeQRCodeContents(Intent intent, String type) {
if (type.equals(Contents.Type.TEXT)) { if (type.equals(Contents.Type.TEXT)) {
String data = intent.getStringExtra(Intents.Encode.DATA); String data = intent.getStringExtra(Intents.Encode.DATA);
if (data != null && data.length() > 0) { if (data != null && data.length() > 0) {
@ -154,7 +190,6 @@ public final class QRCodeEncoder {
} }
} }
} }
return mContents != null && mContents.length() > 0;
} }
private static final class EncodeThread extends Thread { private static final class EncodeThread extends Thread {
@ -164,18 +199,21 @@ public final class QRCodeEncoder {
private final String mContents; private final String mContents;
private final Handler mHandler; private final Handler mHandler;
private final int mPixelResolution; private final int mPixelResolution;
private final BarcodeFormat mFormat;
EncodeThread(String contents, Handler handler, int pixelResolution) { EncodeThread(String contents, Handler handler, int pixelResolution,
BarcodeFormat format) {
mContents = contents; mContents = contents;
mHandler = handler; mHandler = handler;
mPixelResolution = pixelResolution; mPixelResolution = pixelResolution;
mFormat = format;
} }
@Override @Override
public void run() { public void run() {
try { try {
ByteMatrix result = new MultiFormatWriter().encode(mContents, BarcodeFormat.QR_CODE, ByteMatrix result = new MultiFormatWriter().encode(mContents,
mPixelResolution, mPixelResolution); mFormat, mPixelResolution, mPixelResolution);
int width = result.width(); int width = result.width();
int height = result.height(); int height = result.height();
byte[][] array = result.getArray(); byte[][] array = result.getArray();

View file

@ -103,6 +103,7 @@ public final class ShareActivity extends Activity {
Intent intent = new Intent(Intents.Encode.ACTION); Intent intent = new Intent(Intents.Encode.ACTION);
intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT); intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT);
intent.putExtra(Intents.Encode.DATA, clipboard.getText()); intent.putExtra(Intents.Encode.DATA, clipboard.getText());
intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
startActivity(intent); startActivity(intent);
} }
} }
@ -127,6 +128,7 @@ public final class ShareActivity extends Activity {
Intent intent = new Intent(Intents.Encode.ACTION); Intent intent = new Intent(Intents.Encode.ACTION);
intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT); intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT);
intent.putExtra(Intents.Encode.DATA, text); intent.putExtra(Intents.Encode.DATA, text);
intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
startActivity(intent); startActivity(intent);
} }
@ -194,6 +196,8 @@ public final class ShareActivity extends Activity {
Intent intent = new Intent(Intents.Encode.ACTION); Intent intent = new Intent(Intents.Encode.ACTION);
intent.putExtra(Intents.Encode.TYPE, Contents.Type.CONTACT); intent.putExtra(Intents.Encode.TYPE, Contents.Type.CONTACT);
intent.putExtra(Intents.Encode.DATA, bundle); intent.putExtra(Intents.Encode.DATA, bundle);
intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
startActivity(intent); startActivity(intent);
} }
} }

View file

@ -17,6 +17,8 @@
package com.google.zxing; package com.google.zxing;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.ByteMatrix;
import com.google.zxing.oned.EAN13Writer;
import com.google.zxing.oned.EAN8Writer;
import com.google.zxing.qrcode.QRCodeWriter; import com.google.zxing.qrcode.QRCodeWriter;
import java.util.Hashtable; import java.util.Hashtable;
@ -38,9 +40,14 @@ public final class MultiFormatWriter implements Writer {
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height, public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException { Hashtable hints) throws WriterException {
if (format == BarcodeFormat.QR_CODE) { if (format == BarcodeFormat.EAN_8) {
return new EAN8Writer().encode(contents, format, width, height, hints);
} else if (format == BarcodeFormat.EAN_13) {
return new EAN13Writer().encode(contents, format, width, height, hints);
} else if (format == BarcodeFormat.QR_CODE) {
return new QRCodeWriter().encode(contents, format, width, height, hints); return new QRCodeWriter().encode(contents, format, width, height, hints);
} else { }
else {
throw new IllegalArgumentException("No encoder available for format " + format); throw new IllegalArgumentException("No encoder available for format " + format);
} }
} }

View file

@ -40,7 +40,7 @@ public abstract class AbstractUPCEANReader extends AbstractOneDReader implements
/** /**
* Start/end guard pattern. * Start/end guard pattern.
*/ */
private static final int[] START_END_PATTERN = {1, 1, 1,}; static final int[] START_END_PATTERN = {1, 1, 1,};
/** /**
* Pattern marking the middle of a UPC/EAN pattern, separating the two halves. * Pattern marking the middle of a UPC/EAN pattern, separating the two halves.

View file

@ -0,0 +1,124 @@
/*
* Copyright 2009 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.oned;
import java.util.Hashtable;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
/**
* <p>Encapsulates functionality and implementation that is common to UPC and EAN families
* of one-dimensional barcodes.</p>
*
* @author aripollak@gmail.com (Ari Pollak)
*/
public abstract class AbstractUPCEANWriter implements UPCEANWriter {
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height)
throws WriterException {
return encode(contents, format, width, height, null);
}
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
if (contents == null || contents.length() == 0) {
throw new IllegalArgumentException("Found empty contents");
}
if (width < 0 || height < 0) {
throw new IllegalArgumentException("Requested dimensions are too small: "
+ width + 'x' + height);
}
byte[] code = encode(contents);
return renderResult(code, width, height);
}
/** @return a byte array of horizontal pixels (0 = white, 1 = black) */
protected static ByteMatrix renderResult(byte[] code, int width, int height) {
int inputWidth = code.length;
// Add quiet zone on both sides
int fullWidth = inputWidth + (AbstractUPCEANReader.START_END_PATTERN.length << 1);
int outputWidth = Math.max(width, fullWidth);
int outputHeight = Math.max(1, height);
int multiple = outputWidth / fullWidth;
int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
ByteMatrix output = new ByteMatrix(outputHeight, outputWidth);
byte[][] outputArray = output.getArray();
byte[] row = new byte[outputWidth];
// a. Write the white pixels at the left of each row
for (int x = 0; x < leftPadding; x++) {
row[x] = (byte) 255;
}
// 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;
}
/**
* Appends the given pattern to the target array starting at pos.
*
* @param startColor
* starting color - 0 for white, 1 for black
* @return the number of elements added to target.
*/
protected static int appendPattern(byte[] target, int pos, int[] pattern, int startColor) {
if (startColor != 0 && startColor != 1) {
throw new IllegalArgumentException(
"startColor must be either 0 or 1, but got: " + startColor);
}
byte color = (byte) startColor;
int numAdded = 0;
for (int i = 0; i < pattern.length; i++) {
for (int j = 0; j < pattern[i]; j++) {
target[pos] = color;
pos += 1;
numAdded += 1;
}
color ^= 1; // flip color after each segment
}
return numAdded;
}
}

View file

@ -417,7 +417,7 @@ public final class Code128Reader extends AbstractOneDReader {
} }
// Check for ample whitespice following pattern, but, to do this we first need to remember that // Check for ample whitespace following pattern, but, to do this we first need to remember that
// we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left
// to read off. Would be slightly better to properly read. Here we just skip it: // to read off. Would be slightly better to properly read. Here we just skip it:
while (row.get(nextStart)) { while (row.get(nextStart)) {

View file

@ -51,14 +51,14 @@ public final class EAN13Reader extends AbstractUPCEANReader {
// Note that the encoding for '0' uses the same parity as a UPC barcode. Hence // Note that the encoding for '0' uses the same parity as a UPC barcode. Hence
// a UPC barcode can be converted to an EAN-13 barcode by prepending a 0. // a UPC barcode can be converted to an EAN-13 barcode by prepending a 0.
// //
// The encodong is represented by the following array, which is a bit pattern // The encoding is represented by the following array, which is a bit pattern
// using Odd = 0 and Even = 1. For example, 5 is represented by: // using Odd = 0 and Even = 1. For example, 5 is represented by:
// //
// Odd Even Even Odd Odd Even // Odd Even Even Odd Odd Even
// in binary: // in binary:
// 0 1 1 0 0 1 == 0x19 // 0 1 1 0 0 1 == 0x19
// //
private static final int[] FIRST_DIGIT_ENCODINGS = { public static final int[] FIRST_DIGIT_ENCODINGS = {
0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A 0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A
}; };

View file

@ -0,0 +1,82 @@
/*
* Copyright 2009 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.oned;
import java.util.Hashtable;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
/**
* This object renders an EAN13 code as a ByteMatrix 2D array of greyscale
* values.
*
* @author aripollak@gmail.com (Ari Pollak)
*/
public final class EAN13Writer extends AbstractUPCEANWriter {
private static final int codeWidth = 3 + // start guard
(7 * 6) + // left bars
5 + // middle guard
(7 * 6) + // right bars
3; // end guard
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
if (format != BarcodeFormat.EAN_13) {
throw new IllegalArgumentException("Can only encode EAN_13, but got " + format);
}
return super.encode(contents, format, width, height, hints);
}
public byte[] encode(String contents) {
if (contents.length() != 13) {
throw new IllegalArgumentException(
"Requested contents should be 13 digits long, but got " + contents.length());
}
int firstDigit = Integer.parseInt(contents.substring(0, 1));
int parities = EAN13Reader.FIRST_DIGIT_ENCODINGS[firstDigit];
byte[] result = new byte[codeWidth];
int pos = 0;
pos += appendPattern(result, pos, AbstractUPCEANReader.START_END_PATTERN, 1);
// See {@link #EAN13Reader} for a description of how the first digit & left bars are encoded
for (int i = 1; i <= 6; i++) {
int digit = Integer.parseInt(contents.substring(i, i + 1));
if ((parities >> (6 - i) & 1) == 1) {
digit += 10;
}
pos += appendPattern(result, pos, AbstractUPCEANReader.L_AND_G_PATTERNS[digit], 0);
}
pos += appendPattern(result, pos, AbstractUPCEANReader.MIDDLE_PATTERN, 0);
for (int i = 7; i <= 12; i++) {
int digit = Integer.parseInt(contents.substring(i, i + 1));
pos += appendPattern(result, pos, AbstractUPCEANReader.L_PATTERNS[digit], 1);
}
pos += appendPattern(result, pos, AbstractUPCEANReader.START_END_PATTERN, 1);
return result;
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright 2009 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.oned;
import java.util.Hashtable;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
/**
* This object renders an EAN8 code as a ByteMatrix 2D array of greyscale
* values.
*
* @author aripollak@gmail.com (Ari Pollak)
*/
public final class EAN8Writer extends AbstractUPCEANWriter {
private static final int codeWidth = 3 + // start guard
(7 * 4) + // left bars
5 + // middle guard
(7 * 4) + // right bars
3; // end guard
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
if (format != BarcodeFormat.EAN_8) {
throw new IllegalArgumentException("Can only encode EAN_8, but got "
+ format);
}
return super.encode(contents, format, width, height, hints);
}
/** @return a byte array of horizontal pixels (0 = white, 1 = black) */
public byte[] encode(String contents) {
if (contents.length() != 8) {
throw new IllegalArgumentException(
"Requested contents should be 8 digits long, but got " + contents.length());
}
byte[] result = new byte[codeWidth];
int pos = 0;
pos += appendPattern(result, pos, AbstractUPCEANReader.START_END_PATTERN, 1);
for (int i = 0; i <= 3; i++) {
int digit = Integer.parseInt(contents.substring(i, i + 1));
pos += appendPattern(result, pos, AbstractUPCEANReader.L_PATTERNS[digit], 0);
}
pos += appendPattern(result, pos, AbstractUPCEANReader.MIDDLE_PATTERN, 0);
for (int i = 4; i <= 7; i++) {
int digit = Integer.parseInt(contents.substring(i, i + 1));
pos += appendPattern(result, pos, AbstractUPCEANReader.L_PATTERNS[digit], 1);
}
pos += appendPattern(result, pos, AbstractUPCEANReader.START_END_PATTERN, 1);
return result;
}
}

View file

@ -27,7 +27,7 @@ import java.util.Vector;
/** /**
* <p>A reader that can read all available UPC/EAN formats. If a caller wants to try to * <p>A reader that can read all available UPC/EAN formats. If a caller wants to try to
* read all such formats, it is most efficent to use this implementation rather than invoke * read all such formats, it is most efficient to use this implementation rather than invoke
* individual readers.</p> * individual readers.</p>
* *
* @author Sean Owen * @author Sean Owen

View file

@ -21,7 +21,7 @@ import com.google.zxing.Result;
import com.google.zxing.common.BitArray; import com.google.zxing.common.BitArray;
/** /**
* <p>This interfaces captures addtional functionality that readers of * <p>This interfaces captures additional functionality that readers of
* UPC/EAN family of barcodes should expose.</p> * UPC/EAN family of barcodes should expose.</p>
* *
* @author Sean Owen * @author Sean Owen

View file

@ -0,0 +1,29 @@
/*
* Copyright 2009 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.oned;
import com.google.zxing.Writer;
/**
* @author Ari Pollak
*/
public interface UPCEANWriter extends Writer {
/** @return a byte array of horizontal pixels (0 = white, 1 = black) */
byte[] encode(String contents);
}

View file

@ -0,0 +1,40 @@
/*
* Copyright 2009 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.oned;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import junit.framework.TestCase;
/**
* @author Ari Pollak
*/
public final class EAN13WriterTestCase extends TestCase {
public void testEncode() throws WriterException {
String testStr = "00010100010110100111011001100100110111101001110101010110011011011001000010101110010011101000100101000";
ByteMatrix result = new EAN13Writer().encode("5901234123457", BarcodeFormat.EAN_13, testStr.length(), 0);
byte[] row = result.getArray()[0];
for (int i = 0; i < testStr.length(); i++) {
assertEquals("Element " + i, (Integer.parseInt(testStr.substring(i,
i + 1)) == 1) ? 0 : (byte) 255, row[i]);
}
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright 2009 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.oned;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix;
import junit.framework.TestCase;
/**
* @author Ari Pollak
*/
public final class EAN8WriterTestCase extends TestCase {
public void testEncode() throws WriterException {
String testStr = "0001010001011010111101111010110111010101001110111001010001001011100101000";
ByteMatrix result = new EAN8Writer().encode("96385074", BarcodeFormat.EAN_8, testStr.length(), 0);
byte[] row = result.getArray()[0];
/*
for (int i = 0; i < row.length; i++) {
System.out.print(row[i] + 1);
}
System.out.println();
*/
for (int i = 0; i < testStr.length(); i++) {
assertEquals("Element " + i, (Integer.parseInt(testStr.substring(i,
i + 1)) == 1) ? 0 : (byte) 255, row[i]);
}
}
}