📄 datamatrixhighlevelencoder.java
字号:
/*
* 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.
*/
/* $Id: DataMatrixHighLevelEncoder.java,v 1.14 2007/07/13 09:57:05 jmaerki Exp $ */
package org.krysalis.barcode4j.impl.datamatrix;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
* DataMatrix ECC 200 data encoder following the algorithm described in ISO/IEC 16022:200(E) in
* annex S.
*
* @version $Id: DataMatrixHighLevelEncoder.java,v 1.14 2007/07/13 09:57:05 jmaerki Exp $
*/
public class DataMatrixHighLevelEncoder implements DataMatrixConstants {
private static final boolean DEBUG = false;
private static final int ASCII_ENCODATION = 0;
private static final int C40_ENCODATION = 1;
private static final int TEXT_ENCODATION = 2;
private static final int X12_ENCODATION = 3;
private static final int EDIFACT_ENCODATION = 4;
private static final int BASE256_ENCODATION = 5;
private static final String[] ENCODATION_NAMES
= new String[] {"ASCII", "C40", "Text", "ANSI X12", "EDIFACT", "Base 256"};
private static final String DEFAULT_ASCII_ENCODING = "ISO-8859-1";
/**
* 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) {
final String charset = "cp437"; //See 4.4.3 and annex B of ISO/IEC 15438:2001(E)
try {
return msg.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new UnsupportedOperationException(
"Incompatible JVM! The '" + charset + "' charset is not available!");
}
}
private static char randomize253State(char ch, int codewordPosition) {
int pseudoRandom = ((149 * codewordPosition) % 253) + 1;
int tempVariable = ch + pseudoRandom;
if (tempVariable <= 254) {
return (char)tempVariable;
} else {
return (char)(tempVariable - 254);
}
}
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);
}
}
/**
* 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);
}
/**
* 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>,
* <code>SymbolShapeHint.FORCE_SQUARE</code> or <code>SymbolShapeHint.FORCE_RECTANGLE</code>.
* @return the encoded message (the char values range from 0 to 255)
*/
public static String encodeHighLevel(String msg, SymbolShapeHint shape) {
//the codewords 0..255 are encoded as Unicode characters
Encoder[] encoders = new Encoder[] {new ASCIIEncoder(),
new C40Encoder(), new TextEncoder(), new X12Encoder(), new EdifactEncoder(),
new Base256Encoder()};
int encodingMode = ASCII_ENCODATION; //Default mode
EncoderContext context = new EncoderContext(msg, shape);
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();
}
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) {
if (DEBUG) {
System.out.println("Unlatch because symbol isn't filled up");
}
context.writeCodeword('\u00fe'); //Unlatch (254)
}
}
//Padding
StringBuffer codewords = context.codewords;
if (codewords.length() < capacity) {
codewords.append(DataMatrixConstants.PAD);
}
while (codewords.length() < capacity) {
codewords.append(randomize253State(DataMatrixConstants.PAD, codewords.length() + 1));
}
return context.codewords.toString();
}
public static byte[] encodeMsg(String msg) {
try {
return msg.getBytes(DEFAULT_ASCII_ENCODING);
} catch (UnsupportedEncodingException e) {
throw new UnsupportedOperationException("Unsupported encoding: " + e.getMessage());
}
}
private static class EncoderContext {
private String msg;
private SymbolShapeHint shape;
private byte[] encodedMsg;
private StringBuffer codewords;
private int pos = 0;
private int newEncoding = -1;
private DataMatrixSymbolInfo symbolInfo;
private int skipAtEnd = 0;
public EncoderContext(String msg, SymbolShapeHint shape) {
this.msg = msg;
this.shape = shape;
this.encodedMsg = encodeMsg(msg);
this.codewords = new StringBuffer(msg.length());
}
public String getMessage() {
return this.msg;
}
public void setSkipAtEnd(int count) {
this.skipAtEnd = count;
}
public char getCurrentChar() {
return msg.charAt(pos);
}
public byte getCurrentByte() {
return encodedMsg[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 = DataMatrixSymbolInfo.lookup(len, shape);
}
}
public void resetSymbolInfo() {
this.symbolInfo = null;
}
}
private interface Encoder {
int getEncodingMode();
void encode(EncoderContext context);
}
private static class ASCIIEncoder implements Encoder {
public int getEncodingMode() {
return ASCII_ENCODATION;
}
public void encode(EncoderContext context) {
//step B
int n = 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 = lookAheadTest(context.msg, context.pos, getEncodingMode());
if (newMode != getEncodingMode()) {
switch (newMode) {
case BASE256_ENCODATION:
context.writeCodeword(LATCH_TO_BASE256);
context.signalEncoderChange(BASE256_ENCODATION);
return;
case C40_ENCODATION:
context.writeCodeword(LATCH_TO_C40);
context.signalEncoderChange(C40_ENCODATION);
return;
case X12_ENCODATION:
context.writeCodeword(LATCH_TO_ANSIX12);
context.signalEncoderChange(X12_ENCODATION);
break;
case TEXT_ENCODATION:
context.writeCodeword(LATCH_TO_TEXT);
context.signalEncoderChange(TEXT_ENCODATION);
break;
case EDIFACT_ENCODATION:
context.writeCodeword(LATCH_TO_EDIFACT);
context.signalEncoderChange(EDIFACT_ENCODATION);
break;
default:
throw new IllegalStateException("Illegal mode: " + newMode);
}
} else if (isExtendedASCII(c)) {
context.writeCodeword(UPPER_SHIFT);
context.writeCodeword((char)(c - 128 + 1));
context.pos++;
} else {
if (DEBUG) {
if (!isASCII7(c)) {
throw new IllegalArgumentException("Not an ASCII-7 character");
}
}
context.writeCodeword((char)(c + 1));
context.pos++;
}
}
}
}
private static class C40Encoder implements Encoder {
public int getEncodingMode() {
return C40_ENCODATION;
}
public void encode(EncoderContext context) {
//step C
int lastCharSize = -1;
StringBuffer buffer = new StringBuffer();
outerloop: while (context.hasMoreCharacters()) {
char c = context.getCurrentChar();
context.pos++;
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
StringBuffer removed = new StringBuffer();
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 outerloop;
}
int count = buffer.length();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -