mirror of
https://github.com/zxing/zxing.git
synced 2024-11-09 20:44:03 -08:00
Issue 572 port of Data Matrix encoder from barcode4j, adapted for Android, ported by Guillaume Le Biller and stoty47 and adapted a bit more by me
git-svn-id: https://zxing.googlecode.com/svn/trunk@2569 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
2170a1cb0b
commit
a642bdd839
2
AUTHORS
2
AUTHORS
|
@ -37,6 +37,7 @@ evansepdx
|
|||
Erik Barbara
|
||||
Fred Lin (Anobiit)
|
||||
gcstang
|
||||
Guillaume Le Biller
|
||||
Hannes Erven
|
||||
hosigumayuugi
|
||||
hypest (Barcorama project)
|
||||
|
@ -89,6 +90,7 @@ Shiyuan Guo / 郭世元
|
|||
ShumovichY
|
||||
Simon Flannery (Ericsson)
|
||||
Steven Parkes
|
||||
stoty74
|
||||
Suraj Supekar
|
||||
Sven Klinkhamer
|
||||
techinstantdx
|
||||
|
|
62
core/src/com/google/zxing/Dimension.java
Normal file
62
core/src/com/google/zxing/Dimension.java
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2012 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;
|
||||
|
||||
/**
|
||||
* Simply encapsulates a width and height.
|
||||
*/
|
||||
public final class Dimension {
|
||||
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
public Dimension(int width, int height) {
|
||||
if (width < 0 || height < 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof Dimension) {
|
||||
Dimension d = (Dimension) other;
|
||||
return width == d.width && height == d.height;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return width * 32713 + height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return width + "x" + height;
|
||||
}
|
||||
|
||||
}
|
|
@ -35,6 +35,21 @@ public enum EncodeHintType {
|
|||
*/
|
||||
CHARACTER_SET,
|
||||
|
||||
/**
|
||||
* Specifies the matrix shape for Data Matrix (type {@link com.google.zxing.datamatrix.encoder.SymbolShapeHint})
|
||||
*/
|
||||
DATA_MATRIX_SHAPE,
|
||||
|
||||
/**
|
||||
* Specifies a minimum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
|
||||
*/
|
||||
MIN_SIZE,
|
||||
|
||||
/**
|
||||
* Specifies a maximum barcode size (type {@link Dimension}). Only applicable to Data Matrix now.
|
||||
*/
|
||||
MAX_SIZE,
|
||||
|
||||
/**
|
||||
* Specifies margin, in pixels, to use when generating the barcode. The meaning can vary
|
||||
* by format; for example it controls margin before and after the barcode horizontally for
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.google.zxing;
|
||||
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.datamatrix.DataMatrixWriter;
|
||||
import com.google.zxing.oned.CodaBarWriter;
|
||||
import com.google.zxing.oned.Code128Writer;
|
||||
import com.google.zxing.oned.Code39Writer;
|
||||
|
@ -80,6 +81,9 @@ public final class MultiFormatWriter implements Writer {
|
|||
case CODABAR:
|
||||
writer = new CodaBarWriter();
|
||||
break;
|
||||
case DATA_MATRIX:
|
||||
writer = new DataMatrixWriter();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("No encoder available for format " + format);
|
||||
}
|
||||
|
|
178
core/src/com/google/zxing/datamatrix/DataMatrixWriter.java
Normal file
178
core/src/com/google/zxing/datamatrix/DataMatrixWriter.java
Normal file
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* 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.datamatrix;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.Writer;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.datamatrix.encoder.DefaultPlacement;
|
||||
import com.google.zxing.Dimension;
|
||||
import com.google.zxing.datamatrix.encoder.ErrorCorrection;
|
||||
import com.google.zxing.datamatrix.encoder.HighLevelEncoder;
|
||||
import com.google.zxing.datamatrix.encoder.SymbolInfo;
|
||||
import com.google.zxing.datamatrix.encoder.SymbolShapeHint;
|
||||
import com.google.zxing.qrcode.encoder.ByteMatrix;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This object renders a Data Matrix code as a BitMatrix 2D array of greyscale values.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @author Guillaume Le Biller Added to zxing lib.
|
||||
*/
|
||||
public final class DataMatrixWriter implements Writer {
|
||||
|
||||
@Override
|
||||
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height) {
|
||||
return encode(contents, format, width, height, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Map<EncodeHintType,?> hints) {
|
||||
|
||||
if (contents.length() == 0) {
|
||||
throw new IllegalArgumentException("Found empty contents");
|
||||
}
|
||||
|
||||
if (format != BarcodeFormat.DATA_MATRIX) {
|
||||
throw new IllegalArgumentException("Can only encode DATA_MATRIX, but got " + format);
|
||||
}
|
||||
|
||||
if (width < 0 || height < 0) {
|
||||
throw new IllegalArgumentException("Requested dimensions are too small: " + width + 'x' + height);
|
||||
}
|
||||
|
||||
// Try to get force shape & min / max size
|
||||
SymbolShapeHint shape = SymbolShapeHint.FORCE_NONE;
|
||||
Dimension minSize = null;
|
||||
Dimension maxSize = null;
|
||||
if (hints != null) {
|
||||
SymbolShapeHint requestedShape = (SymbolShapeHint) hints.get(EncodeHintType.DATA_MATRIX_SHAPE);
|
||||
if (requestedShape != null) {
|
||||
shape = requestedShape;
|
||||
}
|
||||
Dimension requestedMinSize = (Dimension) hints.get(EncodeHintType.MIN_SIZE);
|
||||
if (requestedMinSize != null) {
|
||||
minSize = requestedMinSize;
|
||||
}
|
||||
Dimension requestedMaxSize = (Dimension) hints.get(EncodeHintType.MAX_SIZE);
|
||||
if (requestedMaxSize != null) {
|
||||
maxSize = requestedMaxSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//1. step: Data encodation
|
||||
String encoded = HighLevelEncoder.encodeHighLevel(contents, shape, minSize, maxSize);
|
||||
|
||||
SymbolInfo symbolInfo = SymbolInfo.lookup(encoded.length(), shape, minSize, maxSize, true);
|
||||
|
||||
//2. step: ECC generation
|
||||
String codewords = ErrorCorrection.encodeECC200(encoded, symbolInfo);
|
||||
|
||||
//3. step: Module placement in Matrix
|
||||
DefaultPlacement placement =
|
||||
new DefaultPlacement(codewords, symbolInfo.getSymbolDataWidth(), symbolInfo.getSymbolDataHeight());
|
||||
placement.place();
|
||||
|
||||
//4. step: low-level encoding
|
||||
return encodeLowLevel(placement, symbolInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the given symbol info to a bit matrix.
|
||||
*
|
||||
* @param placement The DataMatrix placement.
|
||||
* @param symbolInfo The symbol info to encode.
|
||||
* @return The bit matrix generated.
|
||||
*/
|
||||
private static BitMatrix encodeLowLevel(DefaultPlacement placement, SymbolInfo symbolInfo) {
|
||||
int symbolWidth = symbolInfo.getSymbolDataWidth();
|
||||
int symbolHeight = symbolInfo.getSymbolDataHeight();
|
||||
|
||||
ByteMatrix matrix = new ByteMatrix(symbolInfo.getSymbolWidth(), symbolInfo.getSymbolHeight());
|
||||
|
||||
int matrixY = 0;
|
||||
|
||||
for (int y = 0; y < symbolHeight; y++) {
|
||||
// Fill the top edge with alternate 0 / 1
|
||||
int matrixX;
|
||||
if ((y % symbolInfo.matrixHeight) == 0) {
|
||||
matrixX = 0;
|
||||
for (int x = 0; x < symbolInfo.getSymbolWidth(); x++) {
|
||||
matrix.set(matrixX, matrixY, (x % 2) == 0);
|
||||
matrixX++;
|
||||
}
|
||||
matrixY++;
|
||||
}
|
||||
matrixX = 0;
|
||||
for (int x = 0; x < symbolWidth; x++) {
|
||||
// Fill the right edge with full 1
|
||||
if ((x % symbolInfo.matrixWidth) == 0) {
|
||||
matrix.set(matrixX, matrixY, true);
|
||||
matrixX++;
|
||||
}
|
||||
matrix.set(matrixX, matrixY, placement.getBit(x, y));
|
||||
matrixX++;
|
||||
// Fill the right edge with alternate 0 / 1
|
||||
if ((x % symbolInfo.matrixWidth) == symbolInfo.matrixWidth - 1) {
|
||||
matrix.set(matrixX, matrixY, (y % 2) == 0);
|
||||
matrixX++;
|
||||
}
|
||||
}
|
||||
matrixY++;
|
||||
// Fill the bottom edge with full 1
|
||||
if ((y % symbolInfo.matrixHeight) == symbolInfo.matrixHeight - 1) {
|
||||
matrixX = 0;
|
||||
for (int x = 0; x < symbolInfo.getSymbolWidth(); x++) {
|
||||
matrix.set(matrixX, matrixY, true);
|
||||
matrixX++;
|
||||
}
|
||||
matrixY++;
|
||||
}
|
||||
}
|
||||
|
||||
return convertByteMatrixToBitMatrix(matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the ByteMatrix to BitMatrix.
|
||||
*
|
||||
* @param matrix The input matrix.
|
||||
* @return The output matrix.
|
||||
*/
|
||||
private static BitMatrix convertByteMatrixToBitMatrix(ByteMatrix matrix) {
|
||||
int matrixWidgth = matrix.getWidth();
|
||||
int matrixHeight = matrix.getHeight();
|
||||
|
||||
BitMatrix output = new BitMatrix(matrixWidgth, matrixHeight);
|
||||
output.clear();
|
||||
for (int i = 0; i < matrixWidgth; i++) {
|
||||
for (int j = 0; j < matrixHeight; j++) {
|
||||
// Zero is white in the bytematrix
|
||||
if (matrix.get(i, j) == 1) {
|
||||
output.set(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
final class ASCIIEncoder implements Encoder {
|
||||
|
||||
@Override
|
||||
public int getEncodingMode() {
|
||||
return HighLevelEncoder.ASCII_ENCODATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(EncoderContext context) {
|
||||
//step B
|
||||
int n = HighLevelEncoder.determineConsecutiveDigitCount(context.msg, context.pos);
|
||||
if (n >= 2) {
|
||||
context.writeCodeword(encodeASCIIDigits(context.msg.charAt(context.pos),
|
||||
context.msg.charAt(context.pos + 1)));
|
||||
context.pos += 2;
|
||||
} else {
|
||||
char c = context.getCurrentChar();
|
||||
int newMode = HighLevelEncoder.lookAheadTest(context.msg, context.pos, getEncodingMode());
|
||||
if (newMode != getEncodingMode()) {
|
||||
switch (newMode) {
|
||||
case HighLevelEncoder.BASE256_ENCODATION:
|
||||
context.writeCodeword(HighLevelEncoder.LATCH_TO_BASE256);
|
||||
context.signalEncoderChange(HighLevelEncoder.BASE256_ENCODATION);
|
||||
return;
|
||||
case HighLevelEncoder.C40_ENCODATION:
|
||||
context.writeCodeword(HighLevelEncoder.LATCH_TO_C40);
|
||||
context.signalEncoderChange(HighLevelEncoder.C40_ENCODATION);
|
||||
return;
|
||||
case HighLevelEncoder.X12_ENCODATION:
|
||||
context.writeCodeword(HighLevelEncoder.LATCH_TO_ANSIX12);
|
||||
context.signalEncoderChange(HighLevelEncoder.X12_ENCODATION);
|
||||
break;
|
||||
case HighLevelEncoder.TEXT_ENCODATION:
|
||||
context.writeCodeword(HighLevelEncoder.LATCH_TO_TEXT);
|
||||
context.signalEncoderChange(HighLevelEncoder.TEXT_ENCODATION);
|
||||
break;
|
||||
case HighLevelEncoder.EDIFACT_ENCODATION:
|
||||
context.writeCodeword(HighLevelEncoder.LATCH_TO_EDIFACT);
|
||||
context.signalEncoderChange(HighLevelEncoder.EDIFACT_ENCODATION);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Illegal mode: " + newMode);
|
||||
}
|
||||
} else if (HighLevelEncoder.isExtendedASCII(c)) {
|
||||
context.writeCodeword(HighLevelEncoder.UPPER_SHIFT);
|
||||
context.writeCodeword((char) (c - 128 + 1));
|
||||
context.pos++;
|
||||
} else {
|
||||
context.writeCodeword((char) (c + 1));
|
||||
context.pos++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static char encodeASCIIDigits(char digit1, char digit2) {
|
||||
if (HighLevelEncoder.isDigit(digit1) && HighLevelEncoder.isDigit(digit2)) {
|
||||
int num = (digit1 - 48) * 10 + (digit2 - 48);
|
||||
return (char) (num + 130);
|
||||
}
|
||||
throw new IllegalArgumentException("not digits: " + digit1 + digit2);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
final class Base256Encoder implements Encoder {
|
||||
|
||||
@Override
|
||||
public int getEncodingMode() {
|
||||
return HighLevelEncoder.BASE256_ENCODATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(EncoderContext context) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append('\0'); //Initialize length field
|
||||
while (context.hasMoreCharacters()) {
|
||||
char c = context.getCurrentChar();
|
||||
buffer.append(c);
|
||||
|
||||
context.pos++;
|
||||
|
||||
int newMode = HighLevelEncoder.lookAheadTest(context.msg, context.pos, getEncodingMode());
|
||||
if (newMode != getEncodingMode()) {
|
||||
context.signalEncoderChange(newMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
int dataCount = buffer.length() - 1;
|
||||
int lengthFieldSize = 1;
|
||||
int currentSize = context.getCodewordCount() + dataCount + lengthFieldSize;
|
||||
context.updateSymbolInfo(currentSize);
|
||||
boolean mustPad = (context.symbolInfo.dataCapacity - currentSize) > 0;
|
||||
if (context.hasMoreCharacters() || mustPad) {
|
||||
if (dataCount <= 249) {
|
||||
buffer.setCharAt(0, (char) dataCount);
|
||||
} else if (dataCount > 249 && dataCount <= 1555) {
|
||||
buffer.setCharAt(0, (char) ((dataCount / 250) + 249));
|
||||
buffer.insert(1, (char) (dataCount % 250));
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Message length not in valid ranges: " + dataCount);
|
||||
}
|
||||
}
|
||||
for (int i = 0, c = buffer.length(); i < c; i++) {
|
||||
context.writeCodeword(randomize255State(
|
||||
buffer.charAt(i), context.getCodewordCount() + 1));
|
||||
}
|
||||
}
|
||||
|
||||
private static char randomize255State(char ch, int codewordPosition) {
|
||||
int pseudoRandom = ((149 * codewordPosition) % 255) + 1;
|
||||
int tempVariable = ch + pseudoRandom;
|
||||
if (tempVariable <= 255) {
|
||||
return (char) tempVariable;
|
||||
} else {
|
||||
return (char) (tempVariable - 256);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
181
core/src/com/google/zxing/datamatrix/encoder/C40Encoder.java
Normal file
181
core/src/com/google/zxing/datamatrix/encoder/C40Encoder.java
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
class C40Encoder implements Encoder {
|
||||
|
||||
@Override
|
||||
public int getEncodingMode() {
|
||||
return HighLevelEncoder.C40_ENCODATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(EncoderContext context) {
|
||||
//step C
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
while (context.hasMoreCharacters()) {
|
||||
char c = context.getCurrentChar();
|
||||
context.pos++;
|
||||
|
||||
int lastCharSize = encodeChar(c, buffer);
|
||||
|
||||
int unwritten = (buffer.length() / 3) * 2;
|
||||
|
||||
int curCodewordCount = context.getCodewordCount() + unwritten;
|
||||
context.updateSymbolInfo(curCodewordCount);
|
||||
int available = context.symbolInfo.dataCapacity - curCodewordCount;
|
||||
|
||||
if (!context.hasMoreCharacters()) {
|
||||
//Avoid having a single C40 value in the last triplet
|
||||
StringBuilder removed = new StringBuilder();
|
||||
if ((buffer.length() % 3) == 2) {
|
||||
if (available < 2 || available > 2) {
|
||||
lastCharSize = backtrackOneCharacter(context, buffer, removed,
|
||||
lastCharSize);
|
||||
}
|
||||
}
|
||||
while ((buffer.length() % 3) == 1
|
||||
&& ((lastCharSize <= 3 && available != 1) || lastCharSize > 3)) {
|
||||
lastCharSize = backtrackOneCharacter(context, buffer, removed, lastCharSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
int count = buffer.length();
|
||||
if ((count % 3) == 0) {
|
||||
int newMode = HighLevelEncoder.lookAheadTest(context.msg, context.pos, getEncodingMode());
|
||||
if (newMode != getEncodingMode()) {
|
||||
context.signalEncoderChange(newMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
handleEOD(context, buffer);
|
||||
}
|
||||
|
||||
private int backtrackOneCharacter(EncoderContext context,
|
||||
StringBuilder buffer, StringBuilder removed, int lastCharSize) {
|
||||
int count = buffer.length();
|
||||
buffer.delete(count - lastCharSize, count);
|
||||
context.pos--;
|
||||
char c = context.getCurrentChar();
|
||||
lastCharSize = encodeChar(c, removed);
|
||||
context.resetSymbolInfo(); //Deal with possible reduction in symbol size
|
||||
return lastCharSize;
|
||||
}
|
||||
|
||||
static void writeNextTriplet(EncoderContext context, StringBuilder buffer) {
|
||||
context.writeCodewords(encodeToCodewords(buffer, 0));
|
||||
buffer.delete(0, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle "end of data" situations
|
||||
*
|
||||
* @param context the encoder context
|
||||
* @param buffer the buffer with the remaining encoded characters
|
||||
*/
|
||||
void handleEOD(EncoderContext context, StringBuilder buffer) {
|
||||
int unwritten = (buffer.length() / 3) * 2;
|
||||
int rest = buffer.length() % 3;
|
||||
|
||||
int curCodewordCount = context.getCodewordCount() + unwritten;
|
||||
context.updateSymbolInfo(curCodewordCount);
|
||||
int available = context.symbolInfo.dataCapacity - curCodewordCount;
|
||||
|
||||
if (rest == 2) {
|
||||
buffer.append('\0'); //Shift 1
|
||||
while (buffer.length() >= 3) {
|
||||
writeNextTriplet(context, buffer);
|
||||
}
|
||||
if (context.hasMoreCharacters()) {
|
||||
context.writeCodeword(HighLevelEncoder.C40_UNLATCH);
|
||||
}
|
||||
} else if (available == 1 && rest == 1) {
|
||||
while (buffer.length() >= 3) {
|
||||
writeNextTriplet(context, buffer);
|
||||
}
|
||||
if (context.hasMoreCharacters()) {
|
||||
context.writeCodeword(HighLevelEncoder.C40_UNLATCH);
|
||||
} else {
|
||||
//No unlatch
|
||||
}
|
||||
context.pos--;
|
||||
} else if (rest == 0) {
|
||||
while (buffer.length() >= 3) {
|
||||
writeNextTriplet(context, buffer);
|
||||
}
|
||||
if (available > 0 || context.hasMoreCharacters()) {
|
||||
context.writeCodeword(HighLevelEncoder.C40_UNLATCH);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected case. Please report!");
|
||||
}
|
||||
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
|
||||
}
|
||||
|
||||
int encodeChar(char c, StringBuilder sb) {
|
||||
if (c == ' ') {
|
||||
sb.append('\3');
|
||||
return 1;
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
sb.append((char) (c - 48 + 4));
|
||||
return 1;
|
||||
} else if (c >= 'A' && c <= 'Z') {
|
||||
sb.append((char) (c - 65 + 14));
|
||||
return 1;
|
||||
} else if (c >= '\0' && c <= '\u001f') {
|
||||
sb.append('\0'); //Shift 1 Set
|
||||
sb.append(c);
|
||||
return 2;
|
||||
} else if (c >= '!' && c <= '/') {
|
||||
sb.append('\1'); //Shift 2 Set
|
||||
sb.append((char) (c - 33));
|
||||
return 2;
|
||||
} else if (c >= ':' && c <= '@') {
|
||||
sb.append('\1'); //Shift 2 Set
|
||||
sb.append((char) (c - 58 + 15));
|
||||
return 2;
|
||||
} else if (c >= '[' && c <= '_') {
|
||||
sb.append('\1'); //Shift 2 Set
|
||||
sb.append((char) (c - 91 + 22));
|
||||
return 2;
|
||||
} else if (c >= '\u0060' && c <= '\u007f') {
|
||||
sb.append('\2'); //Shift 3 Set
|
||||
sb.append((char) (c - 96));
|
||||
return 2;
|
||||
} else if (c >= '\u0080') {
|
||||
sb.append("\1\u001e"); //Shift 2, Upper Shift
|
||||
int len = 2;
|
||||
len += encodeChar((char) (c - 128), sb);
|
||||
return len;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Illegal character: " + c);
|
||||
}
|
||||
}
|
||||
|
||||
private static String encodeToCodewords(CharSequence sb, int startPos) {
|
||||
char c1 = sb.charAt(startPos);
|
||||
char c2 = sb.charAt(startPos + 1);
|
||||
char c3 = sb.charAt(startPos + 2);
|
||||
int v = (1600 * c1) + (40 * c2) + c3 + 1;
|
||||
char cw1 = (char) (v / 256);
|
||||
char cw2 = (char) (v % 256);
|
||||
return new String(new char[] {cw1, cw2});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2006 Jeremias Maerki
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
final class DataMatrixSymbolInfo144 extends SymbolInfo {
|
||||
|
||||
DataMatrixSymbolInfo144() {
|
||||
super(false, 1558, 620, 22, 22, 36);
|
||||
this.rsBlockData = -1; //special! see below
|
||||
this.rsBlockError = 62;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInterleavedBlockCount() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataLengthForInterleavedBlock(int index) {
|
||||
return (index <= 8) ? 156 : 155;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright 2006 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Symbol Character Placement Program. Adapted from Annex M.1 in ISO/IEC 16022:2000(E).
|
||||
*/
|
||||
public class DefaultPlacement {
|
||||
|
||||
private final String codewords;
|
||||
private final int numrows;
|
||||
private final int numcols;
|
||||
private final byte[] bits;
|
||||
|
||||
/**
|
||||
* Main constructor
|
||||
*
|
||||
* @param codewords the codewords to place
|
||||
* @param numcols the number of columns
|
||||
* @param numrows the number of rows
|
||||
*/
|
||||
public DefaultPlacement(String codewords, int numcols, int numrows) {
|
||||
this.codewords = codewords;
|
||||
this.numcols = numcols;
|
||||
this.numrows = numrows;
|
||||
this.bits = new byte[numcols * numrows];
|
||||
Arrays.fill(this.bits, (byte) -1); //Initialize with "not set" value
|
||||
}
|
||||
|
||||
final int getNumrows() {
|
||||
return numrows;
|
||||
}
|
||||
|
||||
final int getNumcols() {
|
||||
return numcols;
|
||||
}
|
||||
|
||||
final byte[] getBits() {
|
||||
return bits;
|
||||
}
|
||||
|
||||
public final boolean getBit(int col, int row) {
|
||||
return bits[row * numcols + col] == 1;
|
||||
}
|
||||
|
||||
final void setBit(int col, int row, boolean bit) {
|
||||
bits[row * numcols + col] = bit ? (byte) 1 : (byte) 0;
|
||||
}
|
||||
|
||||
final boolean hasBit(int col, int row) {
|
||||
return bits[row * numcols + col] >= 0;
|
||||
}
|
||||
|
||||
public final void place() {
|
||||
int pos = 0;
|
||||
int row = 4;
|
||||
int col = 0;
|
||||
|
||||
do {
|
||||
/* repeatedly first check for one of the special corner cases, then... */
|
||||
if ((row == numrows) && (col == 0)) {
|
||||
corner1(pos++);
|
||||
}
|
||||
if ((row == numrows - 2) && (col == 0) && ((numcols % 4) != 0)) {
|
||||
corner2(pos++);
|
||||
}
|
||||
if ((row == numrows - 2) && (col == 0) && (numcols % 8 == 4)) {
|
||||
corner3(pos++);
|
||||
}
|
||||
if ((row == numrows + 4) && (col == 2) && ((numcols % 8) == 0)) {
|
||||
corner4(pos++);
|
||||
}
|
||||
/* sweep upward diagonally, inserting successive characters... */
|
||||
do {
|
||||
if ((row < numrows) && (col >= 0) && !hasBit(col, row)) {
|
||||
utah(row, col, pos++);
|
||||
}
|
||||
row -= 2;
|
||||
col += 2;
|
||||
} while (row >= 0 && (col < numcols));
|
||||
row++;
|
||||
col += 3;
|
||||
|
||||
/* and then sweep downward diagonally, inserting successive characters, ... */
|
||||
do {
|
||||
if ((row >= 0) && (col < numcols) && !hasBit(col, row)) {
|
||||
utah(row, col, pos++);
|
||||
}
|
||||
row += 2;
|
||||
col -= 2;
|
||||
} while ((row < numrows) && (col >= 0));
|
||||
row += 3;
|
||||
col++;
|
||||
|
||||
/* ...until the entire array is scanned */
|
||||
} while ((row < numrows) || (col < numcols));
|
||||
|
||||
/* Lastly, if the lower righthand corner is untouched, fill in fixed pattern */
|
||||
if (!hasBit(numcols - 1, numrows - 1)) {
|
||||
setBit(numcols - 1, numrows - 1, true);
|
||||
setBit(numcols - 2, numrows - 2, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void module(int row, int col, int pos, int bit) {
|
||||
if (row < 0) {
|
||||
row += numrows;
|
||||
col += 4 - ((numrows + 4) % 8);
|
||||
}
|
||||
if (col < 0) {
|
||||
col += numcols;
|
||||
row += 4 - ((numcols + 4) % 8);
|
||||
}
|
||||
// Note the conversion:
|
||||
int v = codewords.charAt(pos);
|
||||
v &= 1 << (8 - bit);
|
||||
setBit(col, row, v != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the 8 bits of a utah-shaped symbol character in ECC200.
|
||||
*
|
||||
* @param row the row
|
||||
* @param col the column
|
||||
* @param pos character position
|
||||
*/
|
||||
private void utah(int row, int col, int pos) {
|
||||
module(row - 2, col - 2, pos, 1);
|
||||
module(row - 2, col - 1, pos, 2);
|
||||
module(row - 1, col - 2, pos, 3);
|
||||
module(row - 1, col - 1, pos, 4);
|
||||
module(row - 1, col, pos, 5);
|
||||
module(row, col - 2, pos, 6);
|
||||
module(row, col - 1, pos, 7);
|
||||
module(row, col, pos, 8);
|
||||
}
|
||||
|
||||
private void corner1(int pos) {
|
||||
module(numrows - 1, 0, pos, 1);
|
||||
module(numrows - 1, 1, pos, 2);
|
||||
module(numrows - 1, 2, pos, 3);
|
||||
module(0, numcols - 2, pos, 4);
|
||||
module(0, numcols - 1, pos, 5);
|
||||
module(1, numcols - 1, pos, 6);
|
||||
module(2, numcols - 1, pos, 7);
|
||||
module(3, numcols - 1, pos, 8);
|
||||
}
|
||||
|
||||
private void corner2(int pos) {
|
||||
module(numrows - 3, 0, pos, 1);
|
||||
module(numrows - 2, 0, pos, 2);
|
||||
module(numrows - 1, 0, pos, 3);
|
||||
module(0, numcols - 4, pos, 4);
|
||||
module(0, numcols - 3, pos, 5);
|
||||
module(0, numcols - 2, pos, 6);
|
||||
module(0, numcols - 1, pos, 7);
|
||||
module(1, numcols - 1, pos, 8);
|
||||
}
|
||||
|
||||
private void corner3(int pos) {
|
||||
module(numrows - 3, 0, pos, 1);
|
||||
module(numrows - 2, 0, pos, 2);
|
||||
module(numrows - 1, 0, pos, 3);
|
||||
module(0, numcols - 2, pos, 4);
|
||||
module(0, numcols - 1, pos, 5);
|
||||
module(1, numcols - 1, pos, 6);
|
||||
module(2, numcols - 1, pos, 7);
|
||||
module(3, numcols - 1, pos, 8);
|
||||
}
|
||||
|
||||
private void corner4(int pos) {
|
||||
module(numrows - 1, 0, pos, 1);
|
||||
module(numrows - 1, numcols - 1, pos, 2);
|
||||
module(0, numcols - 3, pos, 3);
|
||||
module(0, numcols - 2, pos, 4);
|
||||
module(0, numcols - 1, pos, 5);
|
||||
module(1, numcols - 3, pos, 6);
|
||||
module(1, numcols - 2, pos, 7);
|
||||
module(1, numcols - 1, pos, 8);
|
||||
}
|
||||
|
||||
}
|
137
core/src/com/google/zxing/datamatrix/encoder/EdifactEncoder.java
Normal file
137
core/src/com/google/zxing/datamatrix/encoder/EdifactEncoder.java
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
final class EdifactEncoder implements Encoder {
|
||||
|
||||
@Override
|
||||
public int getEncodingMode() {
|
||||
return HighLevelEncoder.EDIFACT_ENCODATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(EncoderContext context) {
|
||||
//step F
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
while (context.hasMoreCharacters()) {
|
||||
char c = context.getCurrentChar();
|
||||
encodeChar(c, buffer);
|
||||
context.pos++;
|
||||
|
||||
int count = buffer.length();
|
||||
if (count >= 4) {
|
||||
context.writeCodewords(encodeToCodewords(buffer, 0));
|
||||
buffer.delete(0, 4);
|
||||
|
||||
int newMode = HighLevelEncoder.lookAheadTest(context.msg, context.pos, getEncodingMode());
|
||||
if (newMode != getEncodingMode()) {
|
||||
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer.append((char) 31); //Unlatch
|
||||
handleEOD(context, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle "end of data" situations
|
||||
*
|
||||
* @param context the encoder context
|
||||
* @param buffer the buffer with the remaining encoded characters
|
||||
*/
|
||||
private static void handleEOD(EncoderContext context, CharSequence buffer) {
|
||||
try {
|
||||
int count = buffer.length();
|
||||
if (count == 0) {
|
||||
return; //Already finished
|
||||
}
|
||||
if (count == 1) {
|
||||
//Only an unlatch at the end
|
||||
context.updateSymbolInfo();
|
||||
int available = context.symbolInfo.dataCapacity - context.getCodewordCount();
|
||||
int remaining = context.getRemainingCharacters();
|
||||
if (remaining == 0 && available <= 2) {
|
||||
return; //No unlatch
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 4) {
|
||||
throw new IllegalStateException("Count must not exceed 4");
|
||||
}
|
||||
int restChars = count - 1;
|
||||
String encoded = encodeToCodewords(buffer, 0);
|
||||
boolean endOfSymbolReached = !context.hasMoreCharacters();
|
||||
boolean restInAscii = endOfSymbolReached && restChars <= 2;
|
||||
|
||||
if (restChars <= 2) {
|
||||
context.updateSymbolInfo(context.getCodewordCount() + restChars);
|
||||
int available = context.symbolInfo.dataCapacity - context.getCodewordCount();
|
||||
if (available >= 3) {
|
||||
restInAscii = false;
|
||||
context.updateSymbolInfo(context.getCodewordCount() + encoded.length());
|
||||
//available = context.symbolInfo.dataCapacity - context.getCodewordCount();
|
||||
}
|
||||
}
|
||||
|
||||
if (restInAscii) {
|
||||
context.resetSymbolInfo();
|
||||
context.pos -= restChars;
|
||||
} else {
|
||||
context.writeCodewords(encoded);
|
||||
}
|
||||
} finally {
|
||||
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
|
||||
}
|
||||
}
|
||||
|
||||
private static void encodeChar(char c, StringBuilder sb) {
|
||||
if (c >= ' ' && c <= '?') {
|
||||
sb.append(c);
|
||||
} else if (c >= '@' && c <= '^') {
|
||||
sb.append((char) (c - 64));
|
||||
} else {
|
||||
HighLevelEncoder.illegalCharacter(c);
|
||||
}
|
||||
}
|
||||
|
||||
private static String encodeToCodewords(CharSequence sb, int startPos) {
|
||||
int len = sb.length() - startPos;
|
||||
if (len == 0) {
|
||||
throw new IllegalStateException("StringBuilder must not be empty");
|
||||
}
|
||||
char c1 = sb.charAt(startPos);
|
||||
char c2 = len >= 2 ? sb.charAt(startPos + 1) : 0;
|
||||
char c3 = len >= 3 ? sb.charAt(startPos + 2) : 0;
|
||||
char c4 = len >= 4 ? sb.charAt(startPos + 3) : 0;
|
||||
|
||||
int v = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4;
|
||||
char cw1 = (char) ((v >> 16) & 255);
|
||||
char cw2 = (char) ((v >> 8) & 255);
|
||||
char cw3 = (char) (v & 255);
|
||||
StringBuilder res = new StringBuilder(3);
|
||||
res.append(cw1);
|
||||
if (len >= 2) {
|
||||
res.append(cw2);
|
||||
}
|
||||
if (len >= 3) {
|
||||
res.append(cw3);
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
}
|
25
core/src/com/google/zxing/datamatrix/encoder/Encoder.java
Normal file
25
core/src/com/google/zxing/datamatrix/encoder/Encoder.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
interface Encoder {
|
||||
|
||||
int getEncodingMode();
|
||||
|
||||
void encode(EncoderContext context);
|
||||
|
||||
}
|
122
core/src/com/google/zxing/datamatrix/encoder/EncoderContext.java
Normal file
122
core/src/com/google/zxing/datamatrix/encoder/EncoderContext.java
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
import com.google.zxing.Dimension;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
final class EncoderContext {
|
||||
|
||||
String msg;
|
||||
private SymbolShapeHint shape;
|
||||
private Dimension minSize;
|
||||
private Dimension maxSize;
|
||||
StringBuilder codewords;
|
||||
int pos;
|
||||
int newEncoding;
|
||||
SymbolInfo symbolInfo;
|
||||
private int skipAtEnd;
|
||||
|
||||
EncoderContext(String msg) {
|
||||
//From this point on Strings are not Unicode anymore!
|
||||
byte[] msgBinary = msg.getBytes(Charset.forName("ISO-8859-1"));
|
||||
StringBuilder sb = new StringBuilder(msgBinary.length);
|
||||
for (int i = 0, c = msgBinary.length; i < c; i++) {
|
||||
char ch = (char) (msgBinary[i] & 0xff);
|
||||
if (ch == '?' && msg.charAt(i) != '?') {
|
||||
throw new IllegalArgumentException("Message contains characters outside ISO-8859-1 encoding.");
|
||||
}
|
||||
sb.append(ch);
|
||||
}
|
||||
this.msg = sb.toString(); //Not Unicode here!
|
||||
shape = SymbolShapeHint.FORCE_NONE;
|
||||
this.codewords = new StringBuilder(msg.length());
|
||||
newEncoding = -1;
|
||||
}
|
||||
|
||||
public void setSymbolShape(SymbolShapeHint shape) {
|
||||
this.shape = shape;
|
||||
}
|
||||
|
||||
public void setSizeConstraints(Dimension minSize, Dimension maxSize) {
|
||||
this.minSize = minSize;
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.msg;
|
||||
}
|
||||
|
||||
public void setSkipAtEnd(int count) {
|
||||
this.skipAtEnd = count;
|
||||
}
|
||||
|
||||
public char getCurrentChar() {
|
||||
return msg.charAt(pos);
|
||||
}
|
||||
|
||||
public char getCurrent() {
|
||||
return msg.charAt(pos);
|
||||
}
|
||||
|
||||
public void writeCodewords(String codewords) {
|
||||
this.codewords.append(codewords);
|
||||
}
|
||||
|
||||
public void writeCodeword(char codeword) {
|
||||
this.codewords.append(codeword);
|
||||
}
|
||||
|
||||
public int getCodewordCount() {
|
||||
return this.codewords.length();
|
||||
}
|
||||
|
||||
public void signalEncoderChange(int encoding) {
|
||||
this.newEncoding = encoding;
|
||||
}
|
||||
|
||||
public void resetEncoderSignal() {
|
||||
this.newEncoding = -1;
|
||||
}
|
||||
|
||||
public boolean hasMoreCharacters() {
|
||||
return pos < getTotalMessageCharCount();
|
||||
}
|
||||
|
||||
private int getTotalMessageCharCount() {
|
||||
return msg.length() - skipAtEnd;
|
||||
}
|
||||
|
||||
public int getRemainingCharacters() {
|
||||
return getTotalMessageCharCount() - pos;
|
||||
}
|
||||
|
||||
public void updateSymbolInfo() {
|
||||
updateSymbolInfo(getCodewordCount());
|
||||
}
|
||||
|
||||
public void updateSymbolInfo(int len) {
|
||||
if (this.symbolInfo == null || len > this.symbolInfo.dataCapacity) {
|
||||
this.symbolInfo = SymbolInfo.lookup(len, shape, minSize, maxSize, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetSymbolInfo() {
|
||||
this.symbolInfo = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright 2006 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
/**
|
||||
* Error Correction Code for ECC200.
|
||||
*/
|
||||
public final class ErrorCorrection {
|
||||
|
||||
/**
|
||||
* Lookup table which factors to use for which number of error correction codewords.
|
||||
* See FACTORS.
|
||||
*/
|
||||
private static final int[] FACTOR_SETS
|
||||
= {5, 7, 10, 11, 12, 14, 18, 20, 24, 28, 36, 42, 48, 56, 62, 68};
|
||||
|
||||
/**
|
||||
* Precomputed polynomial factors for ECC 200.
|
||||
*/
|
||||
private static final int[][] FACTORS = {
|
||||
{228, 48, 15, 111, 62},
|
||||
{23, 68, 144, 134, 240, 92, 254},
|
||||
{28, 24, 185, 166, 223, 248, 116, 255, 110, 61},
|
||||
{175, 138, 205, 12, 194, 168, 39, 245, 60, 97, 120},
|
||||
{41, 153, 158, 91, 61, 42, 142, 213, 97, 178, 100, 242},
|
||||
{156, 97, 192, 252, 95, 9, 157, 119, 138, 45, 18, 186, 83, 185},
|
||||
{83, 195, 100, 39, 188, 75, 66, 61, 241, 213, 109, 129, 94, 254, 225, 48, 90, 188},
|
||||
{15, 195, 244, 9, 233, 71, 168, 2, 188, 160, 153, 145, 253, 79, 108, 82, 27, 174, 186, 172},
|
||||
{52, 190, 88, 205, 109, 39, 176, 21, 155, 197, 251, 223, 155, 21, 5, 172,
|
||||
254, 124, 12, 181, 184, 96, 50, 193},
|
||||
{211, 231, 43, 97, 71, 96, 103, 174, 37, 151, 170, 53, 75, 34, 249, 121,
|
||||
17, 138, 110, 213, 141, 136, 120, 151, 233, 168, 93, 255},
|
||||
{245, 127, 242, 218, 130, 250, 162, 181, 102, 120, 84, 179, 220, 251, 80, 182,
|
||||
229, 18, 2, 4, 68, 33, 101, 137, 95, 119, 115, 44, 175, 184, 59, 25,
|
||||
225, 98, 81, 112},
|
||||
{77, 193, 137, 31, 19, 38, 22, 153, 247, 105, 122, 2, 245, 133, 242, 8,
|
||||
175, 95, 100, 9, 167, 105, 214, 111, 57, 121, 21, 1, 253, 57, 54, 101,
|
||||
248, 202, 69, 50, 150, 177, 226, 5, 9, 5},
|
||||
{245, 132, 172, 223, 96, 32, 117, 22, 238, 133, 238, 231, 205, 188, 237, 87,
|
||||
191, 106, 16, 147, 118, 23, 37, 90, 170, 205, 131, 88, 120, 100, 66, 138,
|
||||
186, 240, 82, 44, 176, 87, 187, 147, 160, 175, 69, 213, 92, 253, 225, 19},
|
||||
{175, 9, 223, 238, 12, 17, 220, 208, 100, 29, 175, 170, 230, 192, 215, 235,
|
||||
150, 159, 36, 223, 38, 200, 132, 54, 228, 146, 218, 234, 117, 203, 29, 232,
|
||||
144, 238, 22, 150, 201, 117, 62, 207, 164, 13, 137, 245, 127, 67, 247, 28,
|
||||
155, 43, 203, 107, 233, 53, 143, 46},
|
||||
{242, 93, 169, 50, 144, 210, 39, 118, 202, 188, 201, 189, 143, 108, 196, 37,
|
||||
185, 112, 134, 230, 245, 63, 197, 190, 250, 106, 185, 221, 175, 64, 114, 71,
|
||||
161, 44, 147, 6, 27, 218, 51, 63, 87, 10, 40, 130, 188, 17, 163, 31,
|
||||
176, 170, 4, 107, 232, 7, 94, 166, 224, 124, 86, 47, 11, 204},
|
||||
{220, 228, 173, 89, 251, 149, 159, 56, 89, 33, 147, 244, 154, 36, 73, 127,
|
||||
213, 136, 248, 180, 234, 197, 158, 177, 68, 122, 93, 213, 15, 160, 227, 236,
|
||||
66, 139, 153, 185, 202, 167, 179, 25, 220, 232, 96, 210, 231, 136, 223, 239,
|
||||
181, 241, 59, 52, 172, 25, 49, 232, 211, 189, 64, 54, 108, 153, 132, 63,
|
||||
96, 103, 82, 186}};
|
||||
|
||||
private static final int MODULO_VALUE = 0x12D;
|
||||
|
||||
private static final int[] LOG;
|
||||
private static final int[] ALOG;
|
||||
|
||||
static {
|
||||
//Create log and antilog table
|
||||
LOG = new int[256];
|
||||
ALOG = new int[255];
|
||||
|
||||
int p = 1;
|
||||
for (int i = 0; i < 255; i++) {
|
||||
ALOG[i] = p;
|
||||
LOG[p] = i;
|
||||
p <<= 1;
|
||||
if (p >= 256) {
|
||||
p ^= MODULO_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ErrorCorrection() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the ECC200 error correction for an encoded message.
|
||||
*
|
||||
* @param codewords the codewords
|
||||
* @param symbolInfo information about the symbol to be encoded
|
||||
* @return the codewords with interleaved error correction.
|
||||
*/
|
||||
public static String encodeECC200(String codewords, SymbolInfo symbolInfo) {
|
||||
if (codewords.length() != symbolInfo.dataCapacity) {
|
||||
throw new IllegalArgumentException(
|
||||
"The number of codewords does not match the selected symbol");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(symbolInfo.dataCapacity + symbolInfo.errorCodewords);
|
||||
sb.append(codewords);
|
||||
int blockCount = symbolInfo.getInterleavedBlockCount();
|
||||
if (blockCount == 1) {
|
||||
String ecc = createECCBlock(codewords, symbolInfo.errorCodewords);
|
||||
sb.append(ecc);
|
||||
} else {
|
||||
sb.setLength(sb.capacity());
|
||||
int[] dataSizes = new int[blockCount];
|
||||
int[] errorSizes = new int[blockCount];
|
||||
int[] startPos = new int[blockCount];
|
||||
for (int i = 0; i < blockCount; i++) {
|
||||
dataSizes[i] = symbolInfo.getDataLengthForInterleavedBlock(i + 1);
|
||||
errorSizes[i] = symbolInfo.getErrorLengthForInterleavedBlock(i + 1);
|
||||
startPos[i] = 0;
|
||||
if (i > 0) {
|
||||
startPos[i] = startPos[i - 1] + dataSizes[i];
|
||||
}
|
||||
}
|
||||
for (int block = 0; block < blockCount; block++) {
|
||||
StringBuilder temp = new StringBuilder(dataSizes[block]);
|
||||
for (int d = block; d < symbolInfo.dataCapacity; d += blockCount) {
|
||||
temp.append(codewords.charAt(d));
|
||||
}
|
||||
String ecc = createECCBlock(temp.toString(), errorSizes[block]);
|
||||
int pos = 0;
|
||||
for (int e = block; e < errorSizes[block] * blockCount; e += blockCount) {
|
||||
sb.setCharAt(symbolInfo.dataCapacity + e, ecc.charAt(pos++));
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
private static String createECCBlock(CharSequence codewords, int numECWords) {
|
||||
return createECCBlock(codewords, 0, codewords.length(), numECWords);
|
||||
}
|
||||
|
||||
private static String createECCBlock(CharSequence codewords, int start, int len, int numECWords) {
|
||||
int table = -1;
|
||||
for (int i = 0; i < FACTOR_SETS.length; i++) {
|
||||
if (FACTOR_SETS[i] == numECWords) {
|
||||
table = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (table < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal number of error correction codewords specified: " + numECWords);
|
||||
}
|
||||
int[] poly = FACTORS[table];
|
||||
char[] ecc = new char[numECWords];
|
||||
for (int i = 0; i < numECWords; i++) {
|
||||
ecc[i] = 0;
|
||||
}
|
||||
for (int i = start; i < start + len; i++) {
|
||||
int m = ecc[numECWords - 1] ^ codewords.charAt(i);
|
||||
for (int k = numECWords - 1; k > 0; k--) {
|
||||
if (m != 0 && poly[k] != 0) {
|
||||
ecc[k] = (char) (ecc[k - 1] ^ ALOG[(LOG[m] + LOG[poly[k]]) % 255]);
|
||||
} else {
|
||||
ecc[k] = ecc[k - 1];
|
||||
}
|
||||
}
|
||||
if (m != 0 && poly[0] != 0) {
|
||||
ecc[0] = (char) ALOG[(LOG[m] + LOG[poly[0]]) % 255];
|
||||
} else {
|
||||
ecc[0] = 0;
|
||||
}
|
||||
}
|
||||
char[] eccReversed = new char[numECWords];
|
||||
for (int i = 0; i < numECWords; i++) {
|
||||
eccReversed[i] = ecc[numECWords - i - 1];
|
||||
}
|
||||
return String.valueOf(eccReversed);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,446 @@
|
|||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
import com.google.zxing.Dimension;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* DataMatrix ECC 200 data encoder following the algorithm described in ISO/IEC 16022:200(E) in
|
||||
* annex S.
|
||||
*/
|
||||
public final class HighLevelEncoder {
|
||||
|
||||
/**
|
||||
* Padding character
|
||||
*/
|
||||
private static final char PAD = 129;
|
||||
/**
|
||||
* mode latch to C40 encodation mode
|
||||
*/
|
||||
static final char LATCH_TO_C40 = 230;
|
||||
/**
|
||||
* mode latch to Base 256 encodation mode
|
||||
*/
|
||||
static final char LATCH_TO_BASE256 = 231;
|
||||
/**
|
||||
* FNC1 Codeword
|
||||
*/
|
||||
//private static final char FNC1 = 232;
|
||||
/**
|
||||
* Structured Append Codeword
|
||||
*/
|
||||
//private static final char STRUCTURED_APPEND = 233;
|
||||
/**
|
||||
* Reader Programming
|
||||
*/
|
||||
//private static final char READER_PROGRAMMING = 234;
|
||||
/**
|
||||
* Upper Shift
|
||||
*/
|
||||
static final char UPPER_SHIFT = 235;
|
||||
/**
|
||||
* 05 Macro
|
||||
*/
|
||||
private static final char MACRO_05 = 236;
|
||||
/**
|
||||
* 06 Macro
|
||||
*/
|
||||
private static final char MACRO_06 = 237;
|
||||
/**
|
||||
* mode latch to ANSI X.12 encodation mode
|
||||
*/
|
||||
static final char LATCH_TO_ANSIX12 = 238;
|
||||
/**
|
||||
* mode latch to Text encodation mode
|
||||
*/
|
||||
static final char LATCH_TO_TEXT = 239;
|
||||
/**
|
||||
* mode latch to EDIFACT encodation mode
|
||||
*/
|
||||
static final char LATCH_TO_EDIFACT = 240;
|
||||
/**
|
||||
* ECI character (Extended Channel Interpretation)
|
||||
*/
|
||||
//private static final char ECI = 241;
|
||||
|
||||
/**
|
||||
* Unlatch from C40 encodation
|
||||
*/
|
||||
static final char C40_UNLATCH = 254;
|
||||
/**
|
||||
* Unlatch from X12 encodation
|
||||
*/
|
||||
static final char X12_UNLATCH = 254;
|
||||
|
||||
/**
|
||||
* 05 Macro header
|
||||
*/
|
||||
private static final String MACRO_05_HEADER = "[)>\u001E05\u001D";
|
||||
/**
|
||||
* 06 Macro header
|
||||
*/
|
||||
private static final String MACRO_06_HEADER = "[)>\u001E06\u001D";
|
||||
/**
|
||||
* Macro trailer
|
||||
*/
|
||||
private static final String MACRO_TRAILER = "\u001E\u0004";
|
||||
|
||||
static final int ASCII_ENCODATION = 0;
|
||||
static final int C40_ENCODATION = 1;
|
||||
static final int TEXT_ENCODATION = 2;
|
||||
static final int X12_ENCODATION = 3;
|
||||
static final int EDIFACT_ENCODATION = 4;
|
||||
static final int BASE256_ENCODATION = 5;
|
||||
|
||||
private HighLevelEncoder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the message to a byte array using the default encoding (cp437) as defined by the
|
||||
* specification
|
||||
*
|
||||
* @param msg the message
|
||||
* @return the byte array of the message
|
||||
*/
|
||||
public static byte[] getBytesForMessage(String msg) {
|
||||
return msg.getBytes(Charset.forName("cp437")); //See 4.4.3 and annex B of ISO/IEC 15438:2001(E)
|
||||
}
|
||||
|
||||
private static char randomize253State(char ch, int codewordPosition) {
|
||||
int pseudoRandom = ((149 * codewordPosition) % 253) + 1;
|
||||
int tempVariable = ch + pseudoRandom;
|
||||
return tempVariable <= 254 ? (char) tempVariable : (char) (tempVariable - 254);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs message encoding of a DataMatrix message using the algorithm described in annex P
|
||||
* of ISO/IEC 16022:2000(E).
|
||||
*
|
||||
* @param msg the message
|
||||
* @return the encoded message (the char values range from 0 to 255)
|
||||
*/
|
||||
public static String encodeHighLevel(String msg) {
|
||||
return encodeHighLevel(msg, SymbolShapeHint.FORCE_NONE, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs message encoding of a DataMatrix message using the algorithm described in annex P
|
||||
* of ISO/IEC 16022:2000(E).
|
||||
*
|
||||
* @param msg the message
|
||||
* @param shape requested shape. May be {@code SymbolShapeHint.FORCE_NONE},
|
||||
* {@code SymbolShapeHint.FORCE_SQUARE} or {@code SymbolShapeHint.FORCE_RECTANGLE}.
|
||||
* @param minSize the minimum symbol size constraint or null for no constraint
|
||||
* @param maxSize the maximum symbol size constraint or null for no constraint
|
||||
* @return the encoded message (the char values range from 0 to 255)
|
||||
*/
|
||||
public static String encodeHighLevel(String msg,
|
||||
SymbolShapeHint shape,
|
||||
Dimension minSize,
|
||||
Dimension maxSize) {
|
||||
//the codewords 0..255 are encoded as Unicode characters
|
||||
Encoder[] encoders = {
|
||||
new ASCIIEncoder(), new C40Encoder(), new TextEncoder(),
|
||||
new X12Encoder(), new EdifactEncoder(), new Base256Encoder()
|
||||
};
|
||||
|
||||
EncoderContext context = new EncoderContext(msg);
|
||||
context.setSymbolShape(shape);
|
||||
context.setSizeConstraints(minSize, maxSize);
|
||||
|
||||
if (msg.startsWith(MACRO_05_HEADER) && msg.endsWith(MACRO_TRAILER)) {
|
||||
context.writeCodeword(MACRO_05);
|
||||
context.setSkipAtEnd(2);
|
||||
context.pos += MACRO_05_HEADER.length();
|
||||
} else if (msg.startsWith(MACRO_06_HEADER) && msg.endsWith(MACRO_TRAILER)) {
|
||||
context.writeCodeword(MACRO_06);
|
||||
context.setSkipAtEnd(2);
|
||||
context.pos += MACRO_06_HEADER.length();
|
||||
}
|
||||
|
||||
int encodingMode = ASCII_ENCODATION; //Default mode
|
||||
while (context.hasMoreCharacters()) {
|
||||
encoders[encodingMode].encode(context);
|
||||
if (context.newEncoding >= 0) {
|
||||
encodingMode = context.newEncoding;
|
||||
context.resetEncoderSignal();
|
||||
}
|
||||
}
|
||||
int len = context.codewords.length();
|
||||
context.updateSymbolInfo();
|
||||
int capacity = context.symbolInfo.dataCapacity;
|
||||
if (len < capacity) {
|
||||
if (encodingMode != ASCII_ENCODATION && encodingMode != BASE256_ENCODATION) {
|
||||
context.writeCodeword('\u00fe'); //Unlatch (254)
|
||||
}
|
||||
}
|
||||
//Padding
|
||||
StringBuilder codewords = context.codewords;
|
||||
if (codewords.length() < capacity) {
|
||||
codewords.append(PAD);
|
||||
}
|
||||
while (codewords.length() < capacity) {
|
||||
codewords.append(randomize253State(PAD, codewords.length() + 1));
|
||||
}
|
||||
|
||||
return context.codewords.toString();
|
||||
}
|
||||
|
||||
static int lookAheadTest(CharSequence msg, int startpos, int currentMode) {
|
||||
if (startpos >= msg.length()) {
|
||||
return currentMode;
|
||||
}
|
||||
float[] charCounts;
|
||||
//step J
|
||||
if (currentMode == ASCII_ENCODATION) {
|
||||
charCounts = new float[]{0, 1, 1, 1, 1, 1.25f};
|
||||
} else {
|
||||
charCounts = new float[]{1, 2, 2, 2, 2, 2.25f};
|
||||
charCounts[currentMode] = 0;
|
||||
}
|
||||
|
||||
int charsProcessed = 0;
|
||||
while (true) {
|
||||
//step K
|
||||
if ((startpos + charsProcessed) == msg.length()) {
|
||||
int min = Integer.MAX_VALUE;
|
||||
byte[] mins = new byte[6];
|
||||
int[] intCharCounts = new int[6];
|
||||
min = findMinimums(charCounts, intCharCounts, min, mins);
|
||||
int minCount = getMinimumCount(mins);
|
||||
|
||||
if (intCharCounts[ASCII_ENCODATION] == min) {
|
||||
return ASCII_ENCODATION;
|
||||
}
|
||||
if (minCount == 1 && mins[BASE256_ENCODATION] > 0) {
|
||||
return BASE256_ENCODATION;
|
||||
}
|
||||
if (minCount == 1 && mins[EDIFACT_ENCODATION] > 0) {
|
||||
return EDIFACT_ENCODATION;
|
||||
}
|
||||
if (minCount == 1 && mins[TEXT_ENCODATION] > 0) {
|
||||
return TEXT_ENCODATION;
|
||||
}
|
||||
if (minCount == 1 && mins[X12_ENCODATION] > 0) {
|
||||
return X12_ENCODATION;
|
||||
}
|
||||
return C40_ENCODATION;
|
||||
}
|
||||
|
||||
char c = msg.charAt(startpos + charsProcessed);
|
||||
charsProcessed++;
|
||||
|
||||
//step L
|
||||
if (isDigit(c)) {
|
||||
charCounts[ASCII_ENCODATION] += 0.5;
|
||||
} else if (isExtendedASCII(c)) {
|
||||
charCounts[ASCII_ENCODATION] = (int) Math.ceil(charCounts[ASCII_ENCODATION]);
|
||||
charCounts[ASCII_ENCODATION] += 2;
|
||||
} else {
|
||||
charCounts[ASCII_ENCODATION] = (int) Math.ceil(charCounts[ASCII_ENCODATION]);
|
||||
charCounts[ASCII_ENCODATION]++;
|
||||
}
|
||||
|
||||
//step M
|
||||
if (isNativeC40(c)) {
|
||||
charCounts[C40_ENCODATION] += 2.0f / 3.0f;
|
||||
} else if (isExtendedASCII(c)) {
|
||||
charCounts[C40_ENCODATION] += 8.0f / 3.0f;
|
||||
} else {
|
||||
charCounts[C40_ENCODATION] += 4.0f / 3.0f;
|
||||
}
|
||||
|
||||
//step N
|
||||
if (isNativeText(c)) {
|
||||
charCounts[TEXT_ENCODATION] += 2.0f / 3.0f;
|
||||
} else if (isExtendedASCII(c)) {
|
||||
charCounts[TEXT_ENCODATION] += 8.0f / 3.0f;
|
||||
} else {
|
||||
charCounts[TEXT_ENCODATION] += 4.0f / 3.0f;
|
||||
}
|
||||
|
||||
//step O
|
||||
if (isNativeX12(c)) {
|
||||
charCounts[X12_ENCODATION] += 2.0f / 3.0f;
|
||||
} else if (isExtendedASCII(c)) {
|
||||
charCounts[X12_ENCODATION] += 13.0f / 3.0f;
|
||||
} else {
|
||||
charCounts[X12_ENCODATION] += 10.0f / 3.0f;
|
||||
}
|
||||
|
||||
//step P
|
||||
if (isNativeEDIFACT(c)) {
|
||||
charCounts[EDIFACT_ENCODATION] += 3.0f / 4.0f;
|
||||
} else if (isExtendedASCII(c)) {
|
||||
charCounts[EDIFACT_ENCODATION] += 17.0f / 4.0f;
|
||||
} else {
|
||||
charCounts[EDIFACT_ENCODATION] += 13.0f / 4.0f;
|
||||
}
|
||||
|
||||
// step Q
|
||||
if (isSpecialB256(c)) {
|
||||
charCounts[BASE256_ENCODATION] += 4;
|
||||
} else {
|
||||
charCounts[BASE256_ENCODATION]++;
|
||||
}
|
||||
|
||||
//step R
|
||||
if (charsProcessed >= 4) {
|
||||
int[] intCharCounts = new int[6];
|
||||
byte[] mins = new byte[6];
|
||||
findMinimums(charCounts, intCharCounts, Integer.MAX_VALUE, mins);
|
||||
int minCount = getMinimumCount(mins);
|
||||
|
||||
if (intCharCounts[ASCII_ENCODATION] < intCharCounts[BASE256_ENCODATION]
|
||||
&& intCharCounts[ASCII_ENCODATION] < intCharCounts[C40_ENCODATION]
|
||||
&& intCharCounts[ASCII_ENCODATION] < intCharCounts[TEXT_ENCODATION]
|
||||
&& intCharCounts[ASCII_ENCODATION] < intCharCounts[X12_ENCODATION]
|
||||
&& intCharCounts[ASCII_ENCODATION] < intCharCounts[EDIFACT_ENCODATION]) {
|
||||
return ASCII_ENCODATION;
|
||||
}
|
||||
if (intCharCounts[BASE256_ENCODATION] < intCharCounts[ASCII_ENCODATION]
|
||||
|| (mins[C40_ENCODATION] + mins[TEXT_ENCODATION] + mins[X12_ENCODATION] + mins[EDIFACT_ENCODATION]) == 0) {
|
||||
return BASE256_ENCODATION;
|
||||
}
|
||||
if (minCount == 1 && mins[EDIFACT_ENCODATION] > 0) {
|
||||
return EDIFACT_ENCODATION;
|
||||
}
|
||||
if (minCount == 1 && mins[TEXT_ENCODATION] > 0) {
|
||||
return TEXT_ENCODATION;
|
||||
}
|
||||
if (minCount == 1 && mins[X12_ENCODATION] > 0) {
|
||||
return X12_ENCODATION;
|
||||
}
|
||||
if (intCharCounts[C40_ENCODATION] + 1 < intCharCounts[ASCII_ENCODATION]
|
||||
&& intCharCounts[C40_ENCODATION] + 1 < intCharCounts[BASE256_ENCODATION]
|
||||
&& intCharCounts[C40_ENCODATION] + 1 < intCharCounts[EDIFACT_ENCODATION]
|
||||
&& intCharCounts[C40_ENCODATION] + 1 < intCharCounts[TEXT_ENCODATION]) {
|
||||
if (intCharCounts[C40_ENCODATION] < intCharCounts[X12_ENCODATION]) {
|
||||
return C40_ENCODATION;
|
||||
}
|
||||
if (intCharCounts[C40_ENCODATION] == intCharCounts[X12_ENCODATION]) {
|
||||
int p = startpos + charsProcessed + 1;
|
||||
while (p < msg.length()) {
|
||||
char tc = msg.charAt(p);
|
||||
if (isX12TermSep(tc)) {
|
||||
return X12_ENCODATION;
|
||||
}
|
||||
if (!isNativeX12(tc)) {
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return C40_ENCODATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int findMinimums(float[] charCounts, int[] intCharCounts, int min, byte[] mins) {
|
||||
Arrays.fill(mins, (byte) 0);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
intCharCounts[i] = (int) Math.ceil(charCounts[i]);
|
||||
int current = intCharCounts[i];
|
||||
if (min > current) {
|
||||
min = current;
|
||||
Arrays.fill(mins, (byte) 0);
|
||||
}
|
||||
if (min == current) {
|
||||
mins[i]++;
|
||||
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
private static int getMinimumCount(byte[] mins) {
|
||||
int minCount = 0;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
minCount += mins[i];
|
||||
}
|
||||
return minCount;
|
||||
}
|
||||
|
||||
static boolean isDigit(char ch) {
|
||||
return ch >= '0' && ch <= '9';
|
||||
}
|
||||
|
||||
static boolean isExtendedASCII(char ch) {
|
||||
return ch >= 128 && ch <= 255;
|
||||
}
|
||||
|
||||
private static boolean isNativeC40(char ch) {
|
||||
return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z');
|
||||
}
|
||||
|
||||
private static boolean isNativeText(char ch) {
|
||||
return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z');
|
||||
}
|
||||
|
||||
private static boolean isNativeX12(char ch) {
|
||||
return isX12TermSep(ch) || (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z');
|
||||
}
|
||||
|
||||
private static boolean isX12TermSep(char ch) {
|
||||
return (ch == '\r') //CR
|
||||
|| (ch == '*')
|
||||
|| (ch == '>');
|
||||
}
|
||||
|
||||
private static boolean isNativeEDIFACT(char ch) {
|
||||
return ch >= ' ' && ch <= '^';
|
||||
}
|
||||
|
||||
private static boolean isSpecialB256(char ch) {
|
||||
return false; //TODO NOT IMPLEMENTED YET!!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the number of consecutive characters that are encodable using numeric compaction.
|
||||
*
|
||||
* @param msg the message
|
||||
* @param startpos the start position within the message
|
||||
* @return the requested character count
|
||||
*/
|
||||
public static int determineConsecutiveDigitCount(CharSequence msg, int startpos) {
|
||||
int count = 0;
|
||||
int len = msg.length();
|
||||
int idx = startpos;
|
||||
if (idx < len) {
|
||||
char ch = msg.charAt(idx);
|
||||
while (isDigit(ch) && idx < len) {
|
||||
count++;
|
||||
idx++;
|
||||
if (idx < len) {
|
||||
ch = msg.charAt(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void illegalCharacter(char c) {
|
||||
String hex = Integer.toHexString(c);
|
||||
hex = "0000".substring(0, 4 - hex.length()) + hex;
|
||||
throw new IllegalArgumentException("Illegal character: " + c + " (0x" + hex + ')');
|
||||
}
|
||||
|
||||
}
|
232
core/src/com/google/zxing/datamatrix/encoder/SymbolInfo.java
Normal file
232
core/src/com/google/zxing/datamatrix/encoder/SymbolInfo.java
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* Copyright 2006 Jeremias Maerki
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
import com.google.zxing.Dimension;
|
||||
|
||||
/**
|
||||
* Symbol info table for DataMatrix.
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SymbolInfo {
|
||||
|
||||
public static final SymbolInfo[] PROD_SYMBOLS = {
|
||||
new SymbolInfo(false, 3, 5, 8, 8, 1),
|
||||
new SymbolInfo(false, 5, 7, 10, 10, 1),
|
||||
/*rect*/new SymbolInfo(true, 5, 7, 16, 6, 1),
|
||||
new SymbolInfo(false, 8, 10, 12, 12, 1),
|
||||
/*rect*/new SymbolInfo(true, 10, 11, 14, 6, 2),
|
||||
new SymbolInfo(false, 12, 12, 14, 14, 1),
|
||||
/*rect*/new SymbolInfo(true, 16, 14, 24, 10, 1),
|
||||
|
||||
new SymbolInfo(false, 18, 14, 16, 16, 1),
|
||||
new SymbolInfo(false, 22, 18, 18, 18, 1),
|
||||
/*rect*/new SymbolInfo(true, 22, 18, 16, 10, 2),
|
||||
new SymbolInfo(false, 30, 20, 20, 20, 1),
|
||||
/*rect*/new SymbolInfo(true, 32, 24, 16, 14, 2),
|
||||
new SymbolInfo(false, 36, 24, 22, 22, 1),
|
||||
new SymbolInfo(false, 44, 28, 24, 24, 1),
|
||||
/*rect*/new SymbolInfo(true, 49, 28, 22, 14, 2),
|
||||
|
||||
new SymbolInfo(false, 62, 36, 14, 14, 4),
|
||||
new SymbolInfo(false, 86, 42, 16, 16, 4),
|
||||
new SymbolInfo(false, 114, 48, 18, 18, 4),
|
||||
new SymbolInfo(false, 144, 56, 20, 20, 4),
|
||||
new SymbolInfo(false, 174, 68, 22, 22, 4),
|
||||
|
||||
new SymbolInfo(false, 204, 84, 24, 24, 4, 102, 42),
|
||||
new SymbolInfo(false, 280, 112, 14, 14, 16, 140, 56),
|
||||
new SymbolInfo(false, 368, 144, 16, 16, 16, 92, 36),
|
||||
new SymbolInfo(false, 456, 192, 18, 18, 16, 114, 48),
|
||||
new SymbolInfo(false, 576, 224, 20, 20, 16, 144, 56),
|
||||
new SymbolInfo(false, 696, 272, 22, 22, 16, 174, 68),
|
||||
new SymbolInfo(false, 816, 336, 24, 24, 16, 136, 56),
|
||||
new SymbolInfo(false, 1050, 408, 18, 18, 36, 175, 68),
|
||||
new SymbolInfo(false, 1304, 496, 20, 20, 36, 163, 62),
|
||||
new DataMatrixSymbolInfo144(),
|
||||
};
|
||||
|
||||
private static SymbolInfo[] symbols = PROD_SYMBOLS;
|
||||
|
||||
/**
|
||||
* Overrides the symbol info set used by this class. Used for testing purposes.
|
||||
*
|
||||
* @param override the symbol info set to use
|
||||
*/
|
||||
public static void overrideSymbolSet(SymbolInfo[] override) {
|
||||
symbols = override;
|
||||
}
|
||||
|
||||
private final boolean rectangular;
|
||||
final int dataCapacity;
|
||||
final int errorCodewords;
|
||||
public final int matrixWidth;
|
||||
public final int matrixHeight;
|
||||
private final int dataRegions;
|
||||
int rsBlockData;
|
||||
int rsBlockError;
|
||||
|
||||
public SymbolInfo(boolean rectangular, int dataCapacity, int errorCodewords,
|
||||
int matrixWidth, int matrixHeight, int dataRegions) {
|
||||
this(rectangular, dataCapacity, errorCodewords, matrixWidth, matrixHeight, dataRegions,
|
||||
dataCapacity, errorCodewords);
|
||||
}
|
||||
|
||||
private SymbolInfo(boolean rectangular, int dataCapacity, int errorCodewords,
|
||||
int matrixWidth, int matrixHeight, int dataRegions,
|
||||
int rsBlockData, int rsBlockError) {
|
||||
this.rectangular = rectangular;
|
||||
this.dataCapacity = dataCapacity;
|
||||
this.errorCodewords = errorCodewords;
|
||||
this.matrixWidth = matrixWidth;
|
||||
this.matrixHeight = matrixHeight;
|
||||
this.dataRegions = dataRegions;
|
||||
this.rsBlockData = rsBlockData;
|
||||
this.rsBlockError = rsBlockError;
|
||||
}
|
||||
|
||||
public static SymbolInfo lookup(int dataCodewords) {
|
||||
return lookup(dataCodewords, SymbolShapeHint.FORCE_NONE, true);
|
||||
}
|
||||
|
||||
public static SymbolInfo lookup(int dataCodewords, SymbolShapeHint shape) {
|
||||
return lookup(dataCodewords, shape, true);
|
||||
}
|
||||
|
||||
public static SymbolInfo lookup(int dataCodewords, boolean allowRectangular, boolean fail) {
|
||||
SymbolShapeHint shape = allowRectangular
|
||||
? SymbolShapeHint.FORCE_NONE : SymbolShapeHint.FORCE_SQUARE;
|
||||
return lookup(dataCodewords, shape, fail);
|
||||
}
|
||||
|
||||
private static SymbolInfo lookup(int dataCodewords, SymbolShapeHint shape, boolean fail) {
|
||||
return lookup(dataCodewords, shape, null, null, fail);
|
||||
}
|
||||
|
||||
public static SymbolInfo lookup(int dataCodewords,
|
||||
SymbolShapeHint shape,
|
||||
Dimension minSize,
|
||||
Dimension maxSize,
|
||||
boolean fail) {
|
||||
for (SymbolInfo symbol : symbols) {
|
||||
if (shape == SymbolShapeHint.FORCE_SQUARE && symbol.rectangular) {
|
||||
continue;
|
||||
}
|
||||
if (shape == SymbolShapeHint.FORCE_RECTANGLE && !symbol.rectangular) {
|
||||
continue;
|
||||
}
|
||||
if (minSize != null
|
||||
&& (symbol.getSymbolWidth() < minSize.getWidth()
|
||||
|| symbol.getSymbolHeight() < minSize.getHeight())) {
|
||||
continue;
|
||||
}
|
||||
if (maxSize != null
|
||||
&& (symbol.getSymbolWidth() > maxSize.getWidth()
|
||||
|| symbol.getSymbolHeight() > maxSize.getHeight())) {
|
||||
continue;
|
||||
}
|
||||
if (dataCodewords <= symbol.dataCapacity) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
if (fail) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't find a symbol arrangement that matches the message. Data codewords: "
|
||||
+ dataCodewords);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
final int getHorizontalDataRegions() {
|
||||
switch (dataRegions) {
|
||||
case 1:
|
||||
return 1;
|
||||
case 2:
|
||||
return 2;
|
||||
case 4:
|
||||
return 2;
|
||||
case 16:
|
||||
return 4;
|
||||
case 36:
|
||||
return 6;
|
||||
default:
|
||||
throw new IllegalStateException("Cannot handle this number of data regions");
|
||||
}
|
||||
}
|
||||
|
||||
final int getVerticalDataRegions() {
|
||||
switch (dataRegions) {
|
||||
case 1:
|
||||
return 1;
|
||||
case 2:
|
||||
return 1;
|
||||
case 4:
|
||||
return 2;
|
||||
case 16:
|
||||
return 4;
|
||||
case 36:
|
||||
return 6;
|
||||
default:
|
||||
throw new IllegalStateException("Cannot handle this number of data regions");
|
||||
}
|
||||
}
|
||||
|
||||
public final int getSymbolDataWidth() {
|
||||
return getHorizontalDataRegions() * matrixWidth;
|
||||
}
|
||||
|
||||
public final int getSymbolDataHeight() {
|
||||
return getVerticalDataRegions() * matrixHeight;
|
||||
}
|
||||
|
||||
public final int getSymbolWidth() {
|
||||
return getSymbolDataWidth() + (getHorizontalDataRegions() * 2);
|
||||
}
|
||||
|
||||
public final int getSymbolHeight() {
|
||||
return getSymbolDataHeight() + (getVerticalDataRegions() * 2);
|
||||
}
|
||||
|
||||
public int getCodewordCount() {
|
||||
return dataCapacity + errorCodewords;
|
||||
}
|
||||
|
||||
public int getInterleavedBlockCount() {
|
||||
return dataCapacity / rsBlockData;
|
||||
}
|
||||
|
||||
public int getDataLengthForInterleavedBlock(int index) {
|
||||
return rsBlockData;
|
||||
}
|
||||
|
||||
public final int getErrorLengthForInterleavedBlock(int index) {
|
||||
return rsBlockError;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(rectangular ? "Rectangular Symbol:" : "Square Symbol:");
|
||||
sb.append(" data region ").append(matrixWidth).append('x').append(matrixHeight);
|
||||
sb.append(", symbol size ").append(getSymbolWidth()).append('x').append(getSymbolHeight());
|
||||
sb.append(", symbol data size ").append(getSymbolDataWidth()).append('x').append(getSymbolDataHeight());
|
||||
sb.append(", codewords ").append(dataCapacity).append('+').append(errorCodewords);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2007 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
/**
|
||||
* Enumeration for DataMatrix symbol shape hint. It can be used to force square or rectangular
|
||||
* symbols.
|
||||
*/
|
||||
public enum SymbolShapeHint {
|
||||
|
||||
FORCE_NONE,
|
||||
FORCE_SQUARE,
|
||||
FORCE_RECTANGLE,
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
final class TextEncoder extends C40Encoder {
|
||||
|
||||
@Override
|
||||
public int getEncodingMode() {
|
||||
return HighLevelEncoder.TEXT_ENCODATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
int encodeChar(char c, StringBuilder sb) {
|
||||
if (c == ' ') {
|
||||
sb.append('\3');
|
||||
return 1;
|
||||
}
|
||||
if (c >= '0' && c <= '9') {
|
||||
sb.append((char) (c - 48 + 4));
|
||||
return 1;
|
||||
}
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
sb.append((char) (c - 97 + 14));
|
||||
return 1;
|
||||
}
|
||||
if (c >= '\0' && c <= '\u001f') {
|
||||
sb.append('\0'); //Shift 1 Set
|
||||
sb.append(c);
|
||||
return 2;
|
||||
}
|
||||
if (c >= '!' && c <= '/') {
|
||||
sb.append('\1'); //Shift 2 Set
|
||||
sb.append((char) (c - 33));
|
||||
return 2;
|
||||
}
|
||||
if (c >= ':' && c <= '@') {
|
||||
sb.append('\1'); //Shift 2 Set
|
||||
sb.append((char) (c - 58 + 15));
|
||||
return 2;
|
||||
}
|
||||
if (c >= '[' && c <= '_') {
|
||||
sb.append('\1'); //Shift 2 Set
|
||||
sb.append((char) (c - 91 + 22));
|
||||
return 2;
|
||||
}
|
||||
if (c == '\u0060') {
|
||||
sb.append('\2'); //Shift 3 Set
|
||||
sb.append((char) (c - 96));
|
||||
return 2;
|
||||
}
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
sb.append('\2'); //Shift 3 Set
|
||||
sb.append((char) (c - 65 + 1));
|
||||
return 2;
|
||||
}
|
||||
if (c >= '{' && c <= '\u007f') {
|
||||
sb.append('\2'); //Shift 3 Set
|
||||
sb.append((char) (c - 123 + 27));
|
||||
return 2;
|
||||
}
|
||||
if (c >= '\u0080') {
|
||||
sb.append("\1\u001e"); //Shift 2, Upper Shift
|
||||
int len = 2;
|
||||
len += encodeChar((char) (c - 128), sb);
|
||||
return len;
|
||||
}
|
||||
HighLevelEncoder.illegalCharacter(c);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
88
core/src/com/google/zxing/datamatrix/encoder/X12Encoder.java
Normal file
88
core/src/com/google/zxing/datamatrix/encoder/X12Encoder.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright 2006-2007 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
final class X12Encoder extends C40Encoder {
|
||||
|
||||
@Override
|
||||
public int getEncodingMode() {
|
||||
return HighLevelEncoder.X12_ENCODATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(EncoderContext context) {
|
||||
//step C
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
while (context.hasMoreCharacters()) {
|
||||
char c = context.getCurrentChar();
|
||||
context.pos++;
|
||||
|
||||
encodeChar(c, buffer);
|
||||
|
||||
int count = buffer.length();
|
||||
if ((count % 3) == 0) {
|
||||
writeNextTriplet(context, buffer);
|
||||
|
||||
int newMode = HighLevelEncoder.lookAheadTest(context.msg, context.pos, getEncodingMode());
|
||||
if (newMode != getEncodingMode()) {
|
||||
context.signalEncoderChange(newMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
handleEOD(context, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
int encodeChar(char c, StringBuilder sb) {
|
||||
if (c == '\r') {
|
||||
sb.append('\0');
|
||||
} else if (c == '*') {
|
||||
sb.append('\1');
|
||||
} else if (c == '>') {
|
||||
sb.append('\2');
|
||||
} else if (c == ' ') {
|
||||
sb.append('\3');
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
sb.append((char) (c - 48 + 4));
|
||||
} else if (c >= 'A' && c <= 'Z') {
|
||||
sb.append((char) (c - 65 + 14));
|
||||
} else {
|
||||
HighLevelEncoder.illegalCharacter(c);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
void handleEOD(EncoderContext context, StringBuilder buffer) {
|
||||
context.updateSymbolInfo();
|
||||
int available = context.symbolInfo.dataCapacity - context.getCodewordCount();
|
||||
int count = buffer.length();
|
||||
if (count == 2) {
|
||||
context.writeCodeword(HighLevelEncoder.X12_UNLATCH);
|
||||
context.pos -= 2;
|
||||
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
|
||||
} else if (count == 1) {
|
||||
context.pos--;
|
||||
if (available > 1) {
|
||||
context.writeCodeword(HighLevelEncoder.X12_UNLATCH);
|
||||
}
|
||||
//NOP - No unlatch necessary
|
||||
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.datamatrix;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.datamatrix.encoder.SymbolShapeHint;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author satorux@google.com (Satoru Takabayashi) - creator
|
||||
* @author dswitkin@google.com (Daniel Switkin) - ported and expanded from C++
|
||||
*/
|
||||
public final class DataMatrixWriterTestCase extends Assert {
|
||||
|
||||
@Test
|
||||
public void testDataMatrixImageWriter() {
|
||||
DataMatrixWriter writer = new DataMatrixWriter();
|
||||
|
||||
Map<EncodeHintType,Object> hints = new EnumMap<EncodeHintType,Object>(EncodeHintType.class);
|
||||
hints.put(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE);
|
||||
|
||||
int bigEnough = 64;
|
||||
BitMatrix matrix = writer.encode("Hello Google", BarcodeFormat.DATA_MATRIX, bigEnough, bigEnough, hints);
|
||||
assertNotNull(matrix);
|
||||
assertTrue(bigEnough >= matrix.getWidth());
|
||||
assertTrue(bigEnough >= matrix.getHeight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataMatrixWriter() {
|
||||
DataMatrixWriter writer = new DataMatrixWriter();
|
||||
|
||||
Map<EncodeHintType,Object> hints = new EnumMap<EncodeHintType,Object>(EncodeHintType.class);
|
||||
hints.put(EncodeHintType.DATA_MATRIX_SHAPE, SymbolShapeHint.FORCE_SQUARE);
|
||||
|
||||
int bigEnough = 14;
|
||||
BitMatrix matrix = writer.encode("Hello Me", BarcodeFormat.DATA_MATRIX, bigEnough, bigEnough, hints);
|
||||
assertNotNull(matrix);
|
||||
assertEquals(bigEnough, matrix.getWidth());
|
||||
assertEquals(bigEnough, matrix.getHeight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataMatrixTooSmall() {
|
||||
// The DataMatrix will not fit in this size, so the matrix should come back bigger
|
||||
int tooSmall = 8;
|
||||
DataMatrixWriter writer = new DataMatrixWriter();
|
||||
BitMatrix matrix = writer.encode("http://www.google.com/", BarcodeFormat.DATA_MATRIX, tooSmall, tooSmall, null);
|
||||
assertNotNull(matrix);
|
||||
assertTrue(tooSmall < matrix.getWidth());
|
||||
assertTrue(tooSmall < matrix.getHeight());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2006 Jeremias Maerki
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
final class DebugPlacement extends DefaultPlacement {
|
||||
|
||||
DebugPlacement(String codewords, int numcols, int numrows) {
|
||||
super(codewords, numcols, numrows);
|
||||
}
|
||||
|
||||
public String toBitFieldString() {
|
||||
byte[] bits = getBits();
|
||||
StringBuilder sb = new StringBuilder(bits.length);
|
||||
for (byte bit : bits) {
|
||||
sb.append(bit == 1 ? '1' : '0');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
String[] toBitFieldStringArray() {
|
||||
byte[] bits = getBits();
|
||||
int numrows = getNumrows();
|
||||
int numcols = getNumcols();
|
||||
String[] array = new String[numrows];
|
||||
int startpos = 0;
|
||||
for (int row = 0; row < numrows; row++) {
|
||||
StringBuilder sb = new StringBuilder(bits.length);
|
||||
for (int i = 0; i < numcols; i++) {
|
||||
sb.append(bits[startpos + i] == 1 ? '1' : '0');
|
||||
}
|
||||
array[row] = sb.toString();
|
||||
startpos += numcols;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2006 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for the ECC200 error correction.
|
||||
*/
|
||||
public final class ErrorCorrectionTestCase extends Assert {
|
||||
|
||||
@Test
|
||||
public void testRS() {
|
||||
//Sample from Annexe R in ISO/IEC 16022:2000(E)
|
||||
char[] cw = {142, 164, 186};
|
||||
SymbolInfo symbolInfo = SymbolInfo.lookup(3);
|
||||
String s = ErrorCorrection.encodeECC200(String.valueOf(cw), symbolInfo);
|
||||
assertEquals("142 164 186 114 25 5 88 102", HighLevelEncodeTestCase.visualize(s));
|
||||
|
||||
//"A" encoded (ASCII encoding + 2 padding characters)
|
||||
cw = new char[]{66, 129, 70};
|
||||
s = ErrorCorrection.encodeECC200(String.valueOf(cw), symbolInfo);
|
||||
assertEquals("66 129 70 138 234 82 82 95", HighLevelEncodeTestCase.visualize(s));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,379 @@
|
|||
/*
|
||||
* Copyright 2006 Jeremias Maerki.
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
import junit.framework.ComparisonFailure;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link HighLevelEncoder}.
|
||||
*/
|
||||
public final class HighLevelEncodeTestCase extends Assert {
|
||||
|
||||
private static final SymbolInfo[] TEST_SYMBOLS = {
|
||||
new SymbolInfo(false, 3, 5, 8, 8, 1),
|
||||
new SymbolInfo(false, 5, 7, 10, 10, 1),
|
||||
/*rect*/new SymbolInfo(true, 5, 7, 16, 6, 1),
|
||||
new SymbolInfo(false, 8, 10, 12, 12, 1),
|
||||
/*rect*/new SymbolInfo(true, 10, 11, 14, 6, 2),
|
||||
new SymbolInfo(false, 13, 0, 0, 0, 1),
|
||||
new SymbolInfo(false, 77, 0, 0, 0, 1)
|
||||
//The last entries are fake entries to test special conditions with C40 encoding
|
||||
};
|
||||
|
||||
private static void useTestSymbols() {
|
||||
SymbolInfo.overrideSymbolSet(TEST_SYMBOLS);
|
||||
}
|
||||
|
||||
private static void resetSymbols() {
|
||||
SymbolInfo.overrideSymbolSet(SymbolInfo.PROD_SYMBOLS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testASCIIEncodation() {
|
||||
|
||||
String visualized = encodeHighLevel("123456");
|
||||
assertEquals("142 164 186", visualized);
|
||||
|
||||
visualized = encodeHighLevel("123456£");
|
||||
assertEquals("142 164 186 235 36", visualized);
|
||||
|
||||
visualized = encodeHighLevel("30Q324343430794<OQQ");
|
||||
assertEquals("160 82 162 173 173 173 137 224 61 80 82 82", visualized);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testC40EncodationBasic1() {
|
||||
|
||||
String visualized = encodeHighLevel("AIMAIMAIM");
|
||||
assertEquals("230 91 11 91 11 91 11 254", visualized);
|
||||
//230 shifts to C40 encodation, 254 unlatches, "else" case
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testC40EncodationBasic2() {
|
||||
|
||||
String visualized = encodeHighLevel("AIMAIAB");
|
||||
assertEquals("230 91 11 90 255 254 67 129", visualized);
|
||||
//"B" is normally encoded as "15" (one C40 value)
|
||||
//"else" case: "B" is encoded as ASCII
|
||||
|
||||
visualized = encodeHighLevel("AIMAIAb");
|
||||
assertEquals("66 74 78 66 74 66 99 129", visualized); //Encoded as ASCII
|
||||
//Alternative solution:
|
||||
//assertEquals("230 91 11 90 255 254 99 129", visualized);
|
||||
//"b" is normally encoded as "Shift 3, 2" (two C40 values)
|
||||
//"else" case: "b" is encoded as ASCII
|
||||
|
||||
visualized = encodeHighLevel("AIMAIMAIMË");
|
||||
assertEquals("230 91 11 91 11 91 11 254 235 76", visualized);
|
||||
//Alternative solution:
|
||||
//assertEquals("230 91 11 91 11 91 11 11 9 254", visualized);
|
||||
//Expl: 230 = shift to C40, "91 11" = "AIM",
|
||||
//"11 9" = "<EFBFBD>" = "Shift 2, UpperShift, <char>
|
||||
//"else" case
|
||||
|
||||
visualized = encodeHighLevel("AIMAIMAIMë");
|
||||
assertEquals("230 91 11 91 11 91 11 254 235 108", visualized); //Activate when additional rectangulars are available
|
||||
//Expl: 230 = shift to C40, "91 11" = "AIM",
|
||||
//"<EFBFBD>" in C40 encodes to: 1 30 2 11 which doesn't fit into a triplet
|
||||
//"10 243" =
|
||||
//254 = unlatch, 235 = Upper Shift, 108 = <EFBFBD> = 0xEB/235 - 128 + 1
|
||||
//"else" case
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testC40EncodationSpecExample() {
|
||||
//Example in Figure 1 in the spec
|
||||
String visualized = encodeHighLevel("A1B2C3D4E5F6G7H8I9J0K1L2");
|
||||
assertEquals("230 88 88 40 8 107 147 59 67 126 206 78 126 144 121 35 47 254", visualized);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testC40EncodationSpecialCases1() {
|
||||
|
||||
//Special tests avoiding ultra-long test strings because these tests are only used
|
||||
//with the 16x48 symbol (47 data codewords)
|
||||
useTestSymbols();
|
||||
|
||||
String visualized = encodeHighLevel("AIMAIMAIMAIMAIMAIM");
|
||||
assertEquals("230 91 11 91 11 91 11 91 11 91 11 91 11", visualized);
|
||||
//case "a": Unlatch is not required
|
||||
|
||||
visualized = encodeHighLevel("AIMAIMAIMAIMAIMAI");
|
||||
assertEquals("230 91 11 91 11 91 11 91 11 91 11 90 241", visualized);
|
||||
//case "b": Add trailing shift 0 and Unlatch is not required
|
||||
|
||||
visualized = encodeHighLevel("AIMAIMAIMAIMAIMA");
|
||||
assertEquals("230 91 11 91 11 91 11 91 11 91 11 254 66", visualized);
|
||||
//case "c": Unlatch and write last character in ASCII
|
||||
|
||||
resetSymbols();
|
||||
|
||||
visualized = encodeHighLevel("AIMAIMAIMAIMAIMAI");
|
||||
assertEquals("230 91 11 91 11 91 11 91 11 91 11 254 66 74 129 237", visualized);
|
||||
|
||||
visualized = encodeHighLevel("AIMAIMAIMA");
|
||||
assertEquals("230 91 11 91 11 91 11 66", visualized);
|
||||
//case "d": Skip Unlatch and write last character in ASCII
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testC40EncodationSpecialCases2() {
|
||||
|
||||
String visualized = encodeHighLevel("AIMAIMAIMAIMAIMAIMAI");
|
||||
assertEquals("230 91 11 91 11 91 11 91 11 91 11 91 11 254 66 74", visualized);
|
||||
//available > 2, rest = 2 --> unlatch and encode as ASCII
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTextEncodation() {
|
||||
|
||||
String visualized = encodeHighLevel("aimaimaim");
|
||||
assertEquals("239 91 11 91 11 91 11 254", visualized);
|
||||
//239 shifts to Text encodation, 254 unlatches
|
||||
|
||||
visualized = encodeHighLevel("aimaimaim'");
|
||||
assertEquals("239 91 11 91 11 91 11 254 40 129", visualized);
|
||||
//assertEquals("239 91 11 91 11 91 11 7 49 254", visualized);
|
||||
//This is an alternative, but doesn't strictly follow the rules in the spec.
|
||||
|
||||
visualized = encodeHighLevel("aimaimaIm");
|
||||
assertEquals("239 91 11 91 11 87 218 110", visualized);
|
||||
|
||||
visualized = encodeHighLevel("aimaimaimB");
|
||||
assertEquals("239 91 11 91 11 91 11 254 67 129", visualized);
|
||||
|
||||
visualized = encodeHighLevel("aimaimaim{txt}\u0004");
|
||||
assertEquals("239 91 11 91 11 91 11 16 218 236 107 181 69 254 129 237", visualized);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testX12Encodation() {
|
||||
|
||||
//238 shifts to X12 encodation, 254 unlatches
|
||||
|
||||
String visualized = encodeHighLevel("ABC>ABC123>AB");
|
||||
assertEquals("238 89 233 14 192 100 207 44 31 67", visualized);
|
||||
|
||||
visualized = encodeHighLevel("ABC>ABC123>ABC");
|
||||
assertEquals("238 89 233 14 192 100 207 44 31 254 67 68", visualized);
|
||||
|
||||
visualized = encodeHighLevel("ABC>ABC123>ABCD");
|
||||
assertEquals("238 89 233 14 192 100 207 44 31 96 82 254", visualized);
|
||||
|
||||
visualized = encodeHighLevel("ABC>ABC123>ABCDE");
|
||||
assertEquals("238 89 233 14 192 100 207 44 31 96 82 70", visualized);
|
||||
|
||||
visualized = encodeHighLevel("ABC>ABC123>ABCDEF");
|
||||
assertEquals("238 89 233 14 192 100 207 44 31 96 82 254 70 71 129 237", visualized);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEDIFACTEncodation() {
|
||||
|
||||
//240 shifts to EDIFACT encodation
|
||||
|
||||
String visualized = encodeHighLevel(".A.C1.3.DATA.123DATA.123DATA");
|
||||
assertEquals("240 184 27 131 198 236 238 16 21 1 187 28 179 16 21 1 187 28 179 16 21 1",
|
||||
visualized);
|
||||
|
||||
visualized = encodeHighLevel(".A.C1.3.X.X2..");
|
||||
assertEquals("240 184 27 131 198 236 238 98 230 50 47 47", visualized);
|
||||
|
||||
visualized = encodeHighLevel(".A.C1.3.X.X2.");
|
||||
assertEquals("240 184 27 131 198 236 238 98 230 50 47 129", visualized);
|
||||
|
||||
visualized = encodeHighLevel(".A.C1.3.X.X2");
|
||||
assertEquals("240 184 27 131 198 236 238 98 230 50", visualized);
|
||||
|
||||
visualized = encodeHighLevel(".A.C1.3.X.X");
|
||||
assertEquals("240 184 27 131 198 236 238 98 230 31", visualized);
|
||||
|
||||
visualized = encodeHighLevel(".A.C1.3.X.");
|
||||
assertEquals("240 184 27 131 198 236 238 98 231 192", visualized);
|
||||
|
||||
visualized = encodeHighLevel(".A.C1.3.X");
|
||||
assertEquals("240 184 27 131 198 236 238 89", visualized);
|
||||
|
||||
//Checking temporary unlatch from EDIFACT
|
||||
visualized = encodeHighLevel(".XXX.XXX.XXX.XXX.XXX.XXX.üXX.XXX.XXX.XXX.XXX.XXX.XXX");
|
||||
assertEquals("240 185 134 24 185 134 24 185 134 24 185 134 24 185 134 24 185 134 24"
|
||||
+ " 124 47 235 125 240" //<-- this is the temporary unlatch
|
||||
+ " 97 139 152 97 139 152 97 139 152 97 139 152 97 139 152 97 139 152 89 89",
|
||||
visualized);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBase256Encodation() {
|
||||
|
||||
//231 shifts to Base256 encodation
|
||||
|
||||
String visualized = encodeHighLevel("«äöüé»");
|
||||
assertEquals("231 44 108 59 226 126 1 104", visualized);
|
||||
visualized = encodeHighLevel("«äöüéà»");
|
||||
assertEquals("231 51 108 59 226 126 1 141 254 129", visualized);
|
||||
visualized = encodeHighLevel("«äöüéàá»");
|
||||
assertEquals("231 44 108 59 226 126 1 141 36 147", visualized);
|
||||
|
||||
visualized = encodeHighLevel(" 23£"); //ASCII only (for reference)
|
||||
assertEquals("33 153 235 36 129", visualized);
|
||||
|
||||
visualized = encodeHighLevel("«äöüé» 234"); //Mixed Base256 + ASCII
|
||||
assertEquals("231 51 108 59 226 126 1 104 99 153 53 129", visualized);
|
||||
|
||||
visualized = encodeHighLevel("«äöüé» 23£ 1234567890123456789");
|
||||
assertEquals("231 55 108 59 226 126 1 104 99 10 161 167 185 142 164 186 208"
|
||||
+ " 220 142 164 186 208 58 129 59 209 104 254 150 45", visualized);
|
||||
|
||||
visualized = encodeHighLevel(createBinaryMessage(20));
|
||||
assertEquals("231 44 108 59 226 126 1 141 36 5 37 187 80 230 123 17 166 60 210 103 253 150",
|
||||
visualized);
|
||||
visualized = encodeHighLevel(createBinaryMessage(19)); //padding necessary at the end
|
||||
assertEquals("231 63 108 59 226 126 1 141 36 5 37 187 80 230 123 17 166 60 210 103 1 129",
|
||||
visualized);
|
||||
|
||||
visualized = encodeHighLevel(createBinaryMessage(276));
|
||||
assertStartsWith("231 38 219 2 208 120 20 150 35", visualized);
|
||||
assertEndsWith("146 40 194 129", visualized);
|
||||
|
||||
visualized = encodeHighLevel(createBinaryMessage(277));
|
||||
assertStartsWith("231 38 220 2 208 120 20 150 35", visualized);
|
||||
assertEndsWith("146 40 190 87", visualized);
|
||||
}
|
||||
|
||||
private static String createBinaryMessage(int len) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("«äöüéàá-");
|
||||
for (int i = 0; i < len - 9; i++) {
|
||||
sb.append('\u00B7');
|
||||
}
|
||||
sb.append('»');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void assertStartsWith(String expected, String actual) {
|
||||
if (!actual.startsWith(expected)) {
|
||||
throw new ComparisonFailure(null, expected, actual.substring(0, expected.length()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertEndsWith(String expected, String actual) {
|
||||
if (!actual.endsWith(expected)) {
|
||||
throw new ComparisonFailure(null, expected, actual.substring(actual.length() - expected.length()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnlatchingFromC40() {
|
||||
|
||||
String visualized = encodeHighLevel("AIMAIMAIMAIMaimaimaim");
|
||||
assertEquals("230 91 11 91 11 91 11 254 66 74 78 239 91 11 91 11 91 11", visualized);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnlatchingFromText() {
|
||||
|
||||
String visualized = encodeHighLevel("aimaimaimaim12345678");
|
||||
assertEquals("239 91 11 91 11 91 11 91 11 254 142 164 186 208 129 237", visualized);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelloWorld() {
|
||||
|
||||
String visualized = encodeHighLevel("Hello World!");
|
||||
assertEquals("73 239 116 130 175 123 148 64 158 233 254 34", visualized);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug1664266() {
|
||||
//There was an exception and the encoder did not handle the unlatching from
|
||||
//EDIFACT encoding correctly
|
||||
|
||||
String visualized = encodeHighLevel("CREX-TAN:h");
|
||||
assertEquals("240 13 33 88 181 64 78 124 59 105", visualized);
|
||||
|
||||
visualized = encodeHighLevel("CREX-TAN:hh");
|
||||
assertEquals("240 13 33 88 181 64 78 124 59 105 105 129", visualized);
|
||||
|
||||
visualized = encodeHighLevel("CREX-TAN:hhh");
|
||||
assertEquals("240 13 33 88 181 64 78 124 59 105 105 105", visualized);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug3048549() {
|
||||
//There was an IllegalArgumentException for an illegal character here because
|
||||
//of an encoding problem of the character 0x0060 in Java source code.
|
||||
|
||||
String visualized = encodeHighLevel("fiykmj*Rh2`,e6");
|
||||
assertEquals("239 122 87 154 40 7 171 115 207 12 130 71 155 254 129 237", visualized);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMacroCharacters() {
|
||||
|
||||
String visualized = encodeHighLevel("[)>\u001E05\u001D5555\u001C6666\u001E\u0004");
|
||||
//assertEquals("92 42 63 31 135 30 185 185 29 196 196 31 5 129 87 237", visualized);
|
||||
assertEquals("236 185 185 29 196 196 129 56", visualized);
|
||||
}
|
||||
|
||||
// Not passing?
|
||||
/*
|
||||
@Test
|
||||
public void testDataURL() {
|
||||
|
||||
byte[] data = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
|
||||
0x7E, 0x7F, (byte) 0x80, (byte) 0x81, (byte) 0x82};
|
||||
String expected = encodeHighLevel(new String(data, Charset.forName("ISO-8859-1")));
|
||||
String visualized = encodeHighLevel("url(data:text/plain;charset=iso-8859-1,"
|
||||
+ "%00%01%02%03%04%05%06%07%08%09%0A%7E%7F%80%81%82)");
|
||||
assertEquals(expected, visualized);
|
||||
assertEquals("1 2 3 4 5 6 7 8 9 10 11 231 153 173 67 218 112 7", visualized);
|
||||
|
||||
visualized = encodeHighLevel("url(data:;base64,flRlc3R+)");
|
||||
assertEquals("127 85 102 116 117 127 129 56", visualized);
|
||||
}
|
||||
*/
|
||||
|
||||
private static String encodeHighLevel(String msg) {
|
||||
String encoded = HighLevelEncoder.encodeHighLevel(msg);
|
||||
//DecodeHighLevel.decode(encoded);
|
||||
return visualize(encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string of char codewords into a different string which lists each character
|
||||
* using its decimal value.
|
||||
*
|
||||
* @param codewords the codewords
|
||||
* @return the visualized codewords
|
||||
*/
|
||||
static String visualize(CharSequence codewords) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < codewords.length(); i++) {
|
||||
if (i > 0) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append((int) codewords.charAt(i));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2006 Jeremias Maerki
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Tests the DataMatrix placement algorithm.
|
||||
*/
|
||||
public final class PlacementTestCase extends Assert {
|
||||
|
||||
private static final Pattern SPACE = Pattern.compile(" ");
|
||||
|
||||
@Test
|
||||
public void testPlacement() {
|
||||
String codewords = unvisualize("66 74 78 66 74 78 129 56 35 102 192 96 226 100 156 1 107 221"); //"AIMAIM" encoded
|
||||
DebugPlacement placement = new DebugPlacement(codewords, 12, 12);
|
||||
placement.place();
|
||||
String[] expected = {
|
||||
"011100001111",
|
||||
"001010101000",
|
||||
"010001010100",
|
||||
"001010100010",
|
||||
"000111000100",
|
||||
"011000010100",
|
||||
"000100001101",
|
||||
"011000010000",
|
||||
"001100001101",
|
||||
"100010010111",
|
||||
"011101011010",
|
||||
"001011001010"};
|
||||
String[] actual = placement.toBitFieldStringArray();
|
||||
for (int i = 0; i < actual.length; i++) {
|
||||
assertEquals("Row " + i, expected[i], actual[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static String unvisualize(CharSequence visualized) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String token : SPACE.split(visualized)) {
|
||||
sb.append((char) Integer.parseInt(token));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright 2006 Jeremias Maerki
|
||||
*
|
||||
* 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.datamatrix.encoder;
|
||||
|
||||
import com.google.zxing.Dimension;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests the SymbolInfo class.
|
||||
*/
|
||||
public final class SymbolInfoTestCase extends Assert {
|
||||
|
||||
@Test
|
||||
public void testSymbolInfo() {
|
||||
SymbolInfo info = SymbolInfo.lookup(3);
|
||||
assertEquals(5, info.errorCodewords);
|
||||
assertEquals(8, info.matrixWidth);
|
||||
assertEquals(8, info.matrixHeight);
|
||||
assertEquals(10, info.getSymbolWidth());
|
||||
assertEquals(10, info.getSymbolHeight());
|
||||
|
||||
info = SymbolInfo.lookup(3, SymbolShapeHint.FORCE_RECTANGLE);
|
||||
assertEquals(7, info.errorCodewords);
|
||||
assertEquals(16, info.matrixWidth);
|
||||
assertEquals(6, info.matrixHeight);
|
||||
assertEquals(18, info.getSymbolWidth());
|
||||
assertEquals(8, info.getSymbolHeight());
|
||||
|
||||
info = SymbolInfo.lookup(9);
|
||||
assertEquals(11, info.errorCodewords);
|
||||
assertEquals(14, info.matrixWidth);
|
||||
assertEquals(6, info.matrixHeight);
|
||||
assertEquals(32, info.getSymbolWidth());
|
||||
assertEquals(8, info.getSymbolHeight());
|
||||
|
||||
info = SymbolInfo.lookup(9, SymbolShapeHint.FORCE_SQUARE);
|
||||
assertEquals(12, info.errorCodewords);
|
||||
assertEquals(14, info.matrixWidth);
|
||||
assertEquals(14, info.matrixHeight);
|
||||
assertEquals(16, info.getSymbolWidth());
|
||||
assertEquals(16, info.getSymbolHeight());
|
||||
|
||||
try {
|
||||
SymbolInfo.lookup(1559);
|
||||
fail("There's no rectangular symbol for more than 1558 data codewords");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
//expected
|
||||
}
|
||||
try {
|
||||
SymbolInfo.lookup(50, SymbolShapeHint.FORCE_RECTANGLE);
|
||||
fail("There's no rectangular symbol for 50 data codewords");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
//expected
|
||||
}
|
||||
|
||||
info = SymbolInfo.lookup(35);
|
||||
assertEquals(24, info.getSymbolWidth());
|
||||
assertEquals(24, info.getSymbolHeight());
|
||||
|
||||
Dimension fixedSize = new Dimension(26, 26);
|
||||
info = SymbolInfo.lookup(35,
|
||||
SymbolShapeHint.FORCE_NONE, fixedSize, fixedSize, false);
|
||||
assertEquals(26, info.getSymbolWidth());
|
||||
assertEquals(26, info.getSymbolHeight());
|
||||
|
||||
info = SymbolInfo.lookup(45,
|
||||
SymbolShapeHint.FORCE_NONE, fixedSize, fixedSize, false);
|
||||
assertNull(info);
|
||||
|
||||
Dimension minSize = fixedSize;
|
||||
Dimension maxSize = new Dimension(32, 32);
|
||||
|
||||
info = SymbolInfo.lookup(35,
|
||||
SymbolShapeHint.FORCE_NONE, minSize, maxSize, false);
|
||||
assertEquals(26, info.getSymbolWidth());
|
||||
assertEquals(26, info.getSymbolHeight());
|
||||
|
||||
info = SymbolInfo.lookup(40,
|
||||
SymbolShapeHint.FORCE_NONE, minSize, maxSize, false);
|
||||
assertEquals(26, info.getSymbolWidth());
|
||||
assertEquals(26, info.getSymbolHeight());
|
||||
|
||||
info = SymbolInfo.lookup(45,
|
||||
SymbolShapeHint.FORCE_NONE, minSize, maxSize, false);
|
||||
assertEquals(32, info.getSymbolWidth());
|
||||
assertEquals(32, info.getSymbolHeight());
|
||||
|
||||
info = SymbolInfo.lookup(63,
|
||||
SymbolShapeHint.FORCE_NONE, minSize, maxSize, false);
|
||||
assertNull(info);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue