/**
* 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";
/**
- * The type of data being supplied. Use Intent.putExtra(TYPE, type) with one of
- * Contents.Type.
+ * The type of data being supplied if the format is QR Code. Use
+ * Intent.putExtra(TYPE, type) with one of Contents.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 String mContents;
private String mDisplayContents;
private String mTitle;
+ private BarcodeFormat mFormat;
public QRCodeEncoder(Activity activity, Intent intent) {
mActivity = activity;
}
public void requestBarcode(Handler handler, int pixelResolution) {
- Thread encodeThread = new EncodeThread(mContents, handler, pixelResolution);
+ Thread encodeThread = new EncodeThread(mContents, handler, pixelResolution,
+ mFormat);
encodeThread.start();
}
public String getTitle() {
return mTitle;
}
+
+ public String getFormat() {
+ 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.
+ // 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) {
if (intent == null) {
return false;
}
- String type = intent.getStringExtra(Intents.Encode.TYPE);
- if (type == null || type.length() == 0) {
- 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);
+ if (type == null || type.length() == 0) {
+ 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)) {
String data = intent.getStringExtra(Intents.Encode.DATA);
if (data != null && data.length() > 0) {
}
}
}
- return mContents != null && mContents.length() > 0;
}
private static final class EncodeThread extends Thread {
private final String mContents;
private final Handler mHandler;
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;
mHandler = handler;
mPixelResolution = pixelResolution;
+ mFormat = format;
}
@Override
public void run() {
try {
- ByteMatrix result = new MultiFormatWriter().encode(mContents, BarcodeFormat.QR_CODE,
- mPixelResolution, mPixelResolution);
+ ByteMatrix result = new MultiFormatWriter().encode(mContents,
+ mFormat, mPixelResolution, mPixelResolution);
int width = result.width();
int height = result.height();
byte[][] array = result.getArray();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int grey = array[y][x] & 0xff;
- //pixels[y * width + x] = (0xff << 24) | (grey << 16) | (grey << 8) | grey;
+ // pixels[y * width + x] = (0xff << 24) | (grey << 16) | (grey << 8) | grey;
pixels[y * width + x] = 0xff000000 | (0x00010101 * grey);
}
}
Intent intent = new Intent(Intents.Encode.ACTION);
intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT);
intent.putExtra(Intents.Encode.DATA, clipboard.getText());
+ intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
startActivity(intent);
}
}
Intent intent = new Intent(Intents.Encode.ACTION);
intent.putExtra(Intents.Encode.TYPE, Contents.Type.TEXT);
intent.putExtra(Intents.Encode.DATA, text);
+ intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
startActivity(intent);
}
Intent intent = new Intent(Intents.Encode.ACTION);
intent.putExtra(Intents.Encode.TYPE, Contents.Type.CONTACT);
intent.putExtra(Intents.Encode.DATA, bundle);
+ intent.putExtra(Intents.Encode.FORMAT, Contents.Format.QR_CODE);
+
startActivity(intent);
}
}
package com.google.zxing;
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 java.util.Hashtable;
public ByteMatrix encode(String contents, BarcodeFormat format, int width, int height,
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);
- } else {
+ }
+ else {
throw new IllegalArgumentException("No encoder available for format " + format);
}
}
/**
* 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.
--- /dev/null
+/*
+ * 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;
+ }
+}
}
- // 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
// to read off. Would be slightly better to properly read. Here we just skip it:
while (row.get(nextStart)) {
// 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.
//
- // 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:
//
// Odd Even Even Odd Odd Even
// in binary:
// 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
};
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
/**
* <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>
*
* @author Sean Owen
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>
*
* @author Sean Owen
--- /dev/null
+/*
+ * 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);
+
+}
--- /dev/null
+/*
+ * 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]);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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]);
+ }
+ }
+
+}