add CodaBarWriter, and make separation from UPCEANWriter to OneDimensionalCodeWriter and UPCEANWriter which inherits OneDimensionalCodeWriter.

git-svn-id: https://zxing.googlecode.com/svn/trunk@1907 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
dsbnatut 2011-09-15 00:45:54 +00:00
parent 2d59831aa4
commit 02b0816126
6 changed files with 286 additions and 80 deletions

View file

@ -17,6 +17,7 @@
package com.google.zxing; package com.google.zxing;
import com.google.zxing.common.BitMatrix; import com.google.zxing.common.BitMatrix;
import com.google.zxing.oned.CodaBarWriter;
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;
@ -62,6 +63,8 @@ public final class MultiFormatWriter implements Writer {
writer = new ITFWriter(); writer = new ITFWriter();
} else if (format == BarcodeFormat.PDF_417) { } else if (format == BarcodeFormat.PDF_417) {
writer = new PDF417Writer(); writer = new PDF417Writer();
} else if (format == BarcodeFormat.CODABAR) {
writer = new CodaBarWriter();
} else { } else {
throw new IllegalArgumentException("No encoder available for format " + format); throw new IllegalArgumentException("No encoder available for format " + format);
} }

View file

@ -32,14 +32,14 @@ import com.google.zxing.common.BitArray;
public final class CodaBarReader extends OneDReader { public final class CodaBarReader extends OneDReader {
private static final String ALPHABET_STRING = "0123456789-$:/.+ABCDTN"; private static final String ALPHABET_STRING = "0123456789-$:/.+ABCDTN";
private static final char[] ALPHABET = ALPHABET_STRING.toCharArray(); protected static final char[] ALPHABET = ALPHABET_STRING.toCharArray();
/** /**
* These represent the encodings of characters, as patterns of wide and narrow bars. The 7 least-significant bits of * These represent the encodings of characters, as patterns of wide and narrow bars. The 7 least-significant bits of
* each int correspond to the pattern of wide and narrow, with 1s representing "wide" and 0s representing narrow. NOTE * each int correspond to the pattern of wide and narrow, with 1s representing "wide" and 0s representing narrow. NOTE
* : c is equal to the * pattern NOTE : d is equal to the e pattern * : c is equal to the * pattern NOTE : d is equal to the e pattern
*/ */
private static final int[] CHARACTER_ENCODINGS = { protected static final int[] CHARACTER_ENCODINGS = {
0x003, 0x006, 0x009, 0x060, 0x012, 0x042, 0x021, 0x024, 0x030, 0x048, // 0-9 0x003, 0x006, 0x009, 0x060, 0x012, 0x042, 0x021, 0x024, 0x030, 0x048, // 0-9
0x00c, 0x018, 0x045, 0x051, 0x054, 0x015, 0x01A, 0x029, 0x00B, 0x00E, // -$:/.+ABCD 0x00c, 0x018, 0x045, 0x051, 0x054, 0x015, 0x01A, 0x029, 0x00B, 0x00E, // -$:/.+ABCD
0x01A, 0x029 //TN 0x01A, 0x029 //TN
@ -208,7 +208,7 @@ public final class CodaBarReader extends OneDReader {
throw NotFoundException.getNotFoundInstance(); throw NotFoundException.getNotFoundInstance();
} }
private static boolean arrayContains(char[] array, char key) { protected static boolean arrayContains(char[] array, char key) {
if (array != null) { if (array != null) {
for (int i = 0; i < array.length; i++) { for (int i = 0; i < array.length; i++) {
if (array[i] == key) { if (array[i] == key) {

View file

@ -0,0 +1,113 @@
/*
* Copyright 2011 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.common.BitMatrix;
/**
* This class renders CodaBar as {@link BitMatrix}.
*
* @author dsbnatut@gmail.com (Kazuki Nishiura)
*/
public class CodaBarWriter extends OneDimensionalCodeWriter {
public CodaBarWriter() {
// Super constructor requires the sum of the left and right margin length.
// CodaBar spec requires a side margin to be more than ten times wider than narrow space.
// In this implementation, narrow space has a unit length, so 20 is required minimum.
super(20);
}
/*
* @see com.google.zxing.oned.OneDimensionalCodeWriter#encode(java.lang.String)
*/
public byte[] encode(String contents) {
int resultLength;
int position = 0;
// Verify input and calculate decoded length.
if (!CodaBarReader.arrayContains(
new char[]{'A', 'B', 'C', 'D'}, Character.toUpperCase(contents.charAt(0)))) {
throw new IllegalArgumentException(
"Codabar should start with one of the following: 'A', 'B', 'C' or 'D'");
}
if (!CodaBarReader.arrayContains(new char[]{'T', 'N', '*', 'E'},
Character.toUpperCase(contents.charAt(contents.length() - 1)))) {
throw new IllegalArgumentException(
"Codabar should end with one of the following: 'T', 'N', '*' or 'E'");
}
// The start character and the end character are decoded to 10 length each.
resultLength = 20;
char[] charsWhichAreTenLengthEachAfterDecoded = new char[]{'/', ':', '+', '.'};
for (int i = 1; i < contents.length()-1; i++) {
if (Character.isDigit(contents.charAt(i)) || contents.charAt(i) == '-'
|| contents.charAt(i) == '$') {
resultLength += 9;
} else if(CodaBarReader.arrayContains(
charsWhichAreTenLengthEachAfterDecoded, contents.charAt(i))) {
resultLength += 10;
} else {
throw new IllegalArgumentException("Cannot encode : '" + contents.charAt(i) + "'");
}
}
// A blank is placed between each character.
resultLength += contents.length() - 1;
byte[] result = new byte[resultLength];
for (int index = 0; index < contents.length(); index++) {
char c = Character.toUpperCase(contents.charAt(index));
int code = 0;
if (index == contents.length() - 1){
// Neither * nor E are in the CodaBarReader.ALPHABET.
// * is equal to the c pattern, and e is equal to the d pattern
if (c == '*') {
c = 'C';
} else if (c == 'E') {
c = 'D';
}
}
for (int i = 0; i < CodaBarReader.ALPHABET.length; i++) {
// Found any, because I checked above.
if (c == CodaBarReader.ALPHABET[i]) {
code = CodaBarReader.CHARACTER_ENCODINGS[i];
break;
}
}
boolean isBlack = true;
byte color = 1;
int counter = 0;
int bit = 0;
while (bit < 7){ // A character consists of 7 digit.
result[position] = color;
position++;
if (((code >> (6-bit)) & 1) == 0 || counter == 1){
color ^= 1; // Flip the color.
bit++;
counter = 0;
} else {
counter++;
}
}
if (index < contents.length() - 1) {
result[position] = 0;
position++;
}
}
return result;
}
}

View file

@ -0,0 +1,118 @@
/*
* Copyright 2011 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.Writer;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import java.util.Hashtable;
/**
* <p>Encapsulates functionality and implementation that is common to one-dimensional barcodes.</p>
*
* @author dsbnatut@gmail.com (Kazuki Nishiura)
*/
public abstract class OneDimensionalCodeWriter implements Writer {
protected static int sidesMargin;
public OneDimensionalCodeWriter(int sidesMargin) {
this.sidesMargin = sidesMargin;
}
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height)
throws WriterException {
return encode(contents, format, width, height, null);
}
/**
* Encode the contents following specified format.
* {@code width} and {@code height} are required size. This method may return bigger size
* {@code BitMatrix} when specified size is too small. The user can set both {@code width} and
* {@code height} to zero to get minimum size barcode. If negative value is set to {@code width}
* or {@code height}, {@code IllegalArgumentException} is thrown.
*/
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
if (contents == null || contents.length() == 0) {
throw new IllegalArgumentException("Found empty contents");
}
if (width < 0 || height < 0) {
throw new IllegalArgumentException("Negative size is not allowed. Input: "
+ width + 'x' + height);
}
byte[] code = encode(contents);
return renderResult(code, width, height);
}
/** @return a byte array of horizontal pixels (0 = white, 1 = black) */
private static BitMatrix renderResult(byte[] code, int width, int height) {
int inputWidth = code.length;
// Add quiet zone on both sides.
int fullWidth = inputWidth + sidesMargin;
int outputWidth = Math.max(width, fullWidth);
int outputHeight = Math.max(1, height);
int multiple = outputWidth / fullWidth;
int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
BitMatrix output = new BitMatrix(outputWidth, outputHeight);
for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
if (code[inputX] == 1) {
output.setRegion(outputX, 0, multiple, outputHeight);
}
}
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;
}
/**
* Encode the contents to byte array expression of one-dimensional barcode.
* Start code and end code should be included in result, and side margins should not be included.
* @return a byte array of horizontal pixels (0 = white, 1 = black)
* */
public abstract byte[] encode(String contents);
}

View file

@ -16,89 +16,17 @@
package com.google.zxing.oned; package com.google.zxing.oned;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Writer;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import java.util.Hashtable;
/** /**
* <p>Encapsulates functionality and implementation that is common to UPC and EAN families * <p>Encapsulates functionality and implementation that is common to UPC and EAN families
* of one-dimensional barcodes.</p> * of one-dimensional barcodes.</p>
* *
* @author aripollak@gmail.com (Ari Pollak) * @author aripollak@gmail.com (Ari Pollak)
* @author dsbnatut@gmail.com (Kazuki Nishiura)
*/ */
public abstract class UPCEANWriter implements Writer { public abstract class UPCEANWriter extends OneDimensionalCodeWriter {
public UPCEANWriter() {
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height) super(UPCEANReader.START_END_PATTERN.length << 1);
throws WriterException {
return encode(contents, format, width, height, null);
} }
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height,
Hashtable hints) throws WriterException {
if (contents == null || contents.length() == 0) {
throw new IllegalArgumentException("Found empty contents");
}
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) */
private static BitMatrix renderResult(byte[] code, int width, int height) {
int inputWidth = code.length;
// Add quiet zone on both sides
int fullWidth = inputWidth + (UPCEANReader.START_END_PATTERN.length << 1);
int outputWidth = Math.max(width, fullWidth);
int outputHeight = Math.max(1, height);
int multiple = outputWidth / fullWidth;
int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
BitMatrix output = new BitMatrix(outputWidth, outputHeight);
for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {
if (code[inputX] == 1) {
output.setRegion(outputX, 0, multiple, outputHeight);
}
}
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;
}
/** @return a byte array of horizontal pixels (0 = white, 1 = black) */
public abstract byte[] encode(String contents);
} }

View file

@ -0,0 +1,44 @@
/*
* Copyright 2011 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.BitMatrix;
import org.junit.Assert;
import org.junit.Test;
/**
* @author dsbnatut@gmail.com (Kazuki Nishiura)
*/
public final class CodaBarWriterTestCase extends Assert {
@Test
public void testEncode() throws WriterException {
// 1001001011 0 110101001 0 101011001 0 110101001 0 101001101 0 110010101 0 1101101011 0
// 1001001011
String resultStr = "0000000000" +
"1001001011011010100101010110010110101001010100110101100101010110110101101001001011"
+ "0000000000";
BitMatrix result = new CodaBarWriter().encode(
"B515-3/N", BarcodeFormat.CODABAR, resultStr.length(), 0);
for (int i = 0; i < resultStr.length(); i++) {
assertEquals("Element " + i, resultStr.charAt(i) == '1', result.get(i, 0));
}
}
}