All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.google.zxing.datamatrix.encoder.HighLevelEncoder Maven / Gradle / Ivy
/*
* 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.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(int codewordPosition) {
int pseudoRandom = ((149 * codewordPosition) % 253) + 1;
int tempVariable = PAD + pseudoRandom;
return (char) (tempVariable <= 254 ? tempVariable : 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.getNewEncoding() >= 0) {
encodingMode = context.getNewEncoding();
context.resetEncoderSignal();
}
}
int len = context.getCodewordCount();
context.updateSymbolInfo();
int capacity = context.getSymbolInfo().getDataCapacity();
if (len < capacity &&
encodingMode != ASCII_ENCODATION &&
encodingMode != BASE256_ENCODATION &&
encodingMode != EDIFACT_ENCODATION) {
context.writeCodeword('\u00fe'); //Unlatch (254)
}
//Padding
StringBuilder codewords = context.getCodewords();
if (codewords.length() < capacity) {
codewords.append(PAD);
}
while (codewords.length() < capacity) {
codewords.append(randomize253State(codewords.length() + 1));
}
return context.getCodewords().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.5f;
} else if (isExtendedASCII(c)) {
charCounts[ASCII_ENCODATION] = (float) Math.ceil(charCounts[ASCII_ENCODATION]);
charCounts[ASCII_ENCODATION] += 2.0f;
} else {
charCounts[ASCII_ENCODATION] = (float) 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.0f;
} 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 + ')');
}
}