mirror of
https://github.com/zxing/zxing.git
synced 2025-02-02 05:41:08 -08:00
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:
parent
2d59831aa4
commit
02b0816126
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
113
core/src/com/google/zxing/oned/CodaBarWriter.java
Normal file
113
core/src/com/google/zxing/oned/CodaBarWriter.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
118
core/src/com/google/zxing/oned/OneDimensionalCodeWriter.java
Normal file
118
core/src/com/google/zxing/oned/OneDimensionalCodeWriter.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue