moved java files for pre-convert

This commit is contained in:
Henry Schimke
2022-08-20 12:00:19 -05:00
parent 4997291cb8
commit 1901c96559
2757 changed files with 57224 additions and 0 deletions

View File

@@ -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.getMessage(), context.pos);
if (n >= 2) {
context.writeCodeword(encodeASCIIDigits(context.getMessage().charAt(context.pos),
context.getMessage().charAt(context.pos + 1)));
context.pos += 2;
} else {
char c = context.getCurrentChar();
int newMode = HighLevelEncoder.lookAheadTest(context.getMessage(), 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);
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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.getMessage(), context.pos, getEncodingMode());
if (newMode != getEncodingMode()) {
// Return to ASCII encodation, which will actually handle latch to new mode
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
break;
}
}
int dataCount = buffer.length() - 1;
int lengthFieldSize = 1;
int currentSize = context.getCodewordCount() + dataCount + lengthFieldSize;
context.updateSymbolInfo(currentSize);
boolean mustPad = (context.getSymbolInfo().getDataCapacity() - currentSize) > 0;
if (context.hasMoreCharacters() || mustPad) {
if (dataCount <= 249) {
buffer.setCharAt(0, (char) dataCount);
} else if (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);
}
}
}

View File

@@ -0,0 +1,212 @@
/*
* 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;
}
void encodeMaximal(EncoderContext context) {
StringBuilder buffer = new StringBuilder();
int lastCharSize = 0;
int backtrackStartPosition = context.pos;
int backtrackBufferLength = 0;
while (context.hasMoreCharacters()) {
char c = context.getCurrentChar();
context.pos++;
lastCharSize = encodeChar(c, buffer);
if (buffer.length() % 3 == 0) {
backtrackStartPosition = context.pos;
backtrackBufferLength = buffer.length();
}
}
if (backtrackBufferLength != buffer.length()) {
int unwritten = (buffer.length() / 3) * 2;
int curCodewordCount = context.getCodewordCount() + unwritten + 1; // +1 for the latch to C40
context.updateSymbolInfo(curCodewordCount);
int available = context.getSymbolInfo().getDataCapacity() - curCodewordCount;
int rest = buffer.length() % 3;
if ((rest == 2 && available != 2) ||
(rest == 1 && (lastCharSize > 3 || available != 1))) {
buffer.setLength(backtrackBufferLength);
context.pos = backtrackStartPosition;
}
}
if (buffer.length() > 0) {
context.writeCodeword(HighLevelEncoder.LATCH_TO_C40);
}
handleEOD(context, buffer);
}
@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.getSymbolInfo().getDataCapacity() - curCodewordCount;
if (!context.hasMoreCharacters()) {
//Avoid having a single C40 value in the last triplet
StringBuilder removed = new StringBuilder();
if ((buffer.length() % 3) == 2 && available != 2) {
lastCharSize = backtrackOneCharacter(context, buffer, removed, lastCharSize);
}
while ((buffer.length() % 3) == 1 && (lastCharSize > 3 || available != 1)) {
lastCharSize = backtrackOneCharacter(context, buffer, removed, lastCharSize);
}
break;
}
int count = buffer.length();
if ((count % 3) == 0) {
int newMode = HighLevelEncoder.lookAheadTest(context.getMessage(), context.pos, getEncodingMode());
if (newMode != getEncodingMode()) {
// Return to ASCII encodation, which will actually handle latch to new mode
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
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));
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.getSymbolInfo().getDataCapacity() - 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;
}
if (c >= '0' && c <= '9') {
sb.append((char) (c - 48 + 4));
return 1;
}
if (c >= 'A' && c <= 'Z') {
sb.append((char) (c - 65 + 14));
return 1;
}
if (c < ' ') {
sb.append('\0'); //Shift 1 Set
sb.append(c);
return 2;
}
if (c <= '/') {
sb.append('\1'); //Shift 2 Set
sb.append((char) (c - 33));
return 2;
}
if (c <= '@') {
sb.append('\1'); //Shift 2 Set
sb.append((char) (c - 58 + 15));
return 2;
}
if (c <= '_') {
sb.append('\1'); //Shift 2 Set
sb.append((char) (c - 91 + 22));
return 2;
}
if (c <= 127) {
sb.append('\2'); //Shift 3 Set
sb.append((char) (c - 96));
return 2;
}
sb.append("\1\u001e"); //Shift 2, Upper Shift
int len = 2;
len += encodeChar((char) (c - 128), sb);
return len;
}
private static String encodeToCodewords(CharSequence sb) {
int v = (1600 * sb.charAt(0)) + (40 * sb.charAt(1)) + sb.charAt(2) + 1;
char cw1 = (char) (v / 256);
char cw2 = (char) (v % 256);
return new String(new char[] {cw1, cw2});
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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, -1, 62);
}
@Override
public int getInterleavedBlockCount() {
return 10;
}
@Override
public int getDataLengthForInterleavedBlock(int index) {
return (index <= 8) ? 156 : 155;
}
}

View File

@@ -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 CharSequence 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(CharSequence 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;
}
private void setBit(int col, int row, boolean bit) {
bits[row * numcols + col] = (byte) (bit ? 1 : 0);
}
private boolean noBit(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) && noBit(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) && noBit(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 right-hand corner is untouched, fill in fixed pattern
if (noBit(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);
}
}

View File

@@ -0,0 +1,143 @@
/*
* 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));
buffer.delete(0, 4);
int newMode = HighLevelEncoder.lookAheadTest(context.getMessage(), context.pos, getEncodingMode());
if (newMode != getEncodingMode()) {
// Return to ASCII encodation, which will actually handle latch to new mode
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.getSymbolInfo().getDataCapacity() - context.getCodewordCount();
int remaining = context.getRemainingCharacters();
// The following two lines are a hack inspired by the 'fix' from https://sourceforge.net/p/barcode4j/svn/221/
if (remaining > available) {
context.updateSymbolInfo(context.getCodewordCount() + 1);
available = context.getSymbolInfo().getDataCapacity() - context.getCodewordCount();
}
if (remaining <= available && available <= 2) {
return; //No unlatch
}
}
if (count > 4) {
throw new IllegalStateException("Count must not exceed 4");
}
int restChars = count - 1;
String encoded = encodeToCodewords(buffer);
boolean endOfSymbolReached = !context.hasMoreCharacters();
boolean restInAscii = endOfSymbolReached && restChars <= 2;
if (restChars <= 2) {
context.updateSymbolInfo(context.getCodewordCount() + restChars);
int available = context.getSymbolInfo().getDataCapacity() - 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 len = sb.length();
if (len == 0) {
throw new IllegalStateException("StringBuilder must not be empty");
}
char c1 = sb.charAt(0);
char c2 = len >= 2 ? sb.charAt(1) : 0;
char c3 = len >= 3 ? sb.charAt(2) : 0;
char c4 = len >= 4 ? sb.charAt(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();
}
}

View 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);
}

View File

@@ -0,0 +1,134 @@
/*
* 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.StandardCharsets;
final class EncoderContext {
private final String msg;
private SymbolShapeHint shape;
private Dimension minSize;
private Dimension maxSize;
private final StringBuilder codewords;
int pos;
private int newEncoding;
private SymbolInfo symbolInfo;
private int skipAtEnd;
EncoderContext(String msg) {
//From this point on Strings are not Unicode anymore!
byte[] msgBinary = msg.getBytes(StandardCharsets.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 StringBuilder getCodewords() {
return codewords;
}
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 int getNewEncoding() {
return newEncoding;
}
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 SymbolInfo getSymbolInfo() {
return symbolInfo;
}
public void updateSymbolInfo() {
updateSymbolInfo(getCodewordCount());
}
public void updateSymbolInfo(int len) {
if (this.symbolInfo == null || len > this.symbolInfo.getDataCapacity()) {
this.symbolInfo = SymbolInfo.lookup(len, shape, minSize, maxSize, true);
}
}
public void resetSymbolInfo() {
this.symbolInfo = null;
}
}

View File

@@ -0,0 +1,175 @@
/*
* 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 *= 2;
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.getDataCapacity()) {
throw new IllegalArgumentException(
"The number of codewords does not match the selected symbol");
}
StringBuilder sb = new StringBuilder(symbolInfo.getDataCapacity() + symbolInfo.getErrorCodewords());
sb.append(codewords);
int blockCount = symbolInfo.getInterleavedBlockCount();
if (blockCount == 1) {
String ecc = createECCBlock(codewords, symbolInfo.getErrorCodewords());
sb.append(ecc);
} else {
sb.setLength(sb.capacity());
int[] dataSizes = new int[blockCount];
int[] errorSizes = new int[blockCount];
for (int i = 0; i < blockCount; i++) {
dataSizes[i] = symbolInfo.getDataLengthForInterleavedBlock(i + 1);
errorSizes[i] = symbolInfo.getErrorLengthForInterleavedBlock(i + 1);
}
for (int block = 0; block < blockCount; block++) {
StringBuilder temp = new StringBuilder(dataSizes[block]);
for (int d = block; d < symbolInfo.getDataCapacity(); 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.getDataCapacity() + e, ecc.charAt(pos++));
}
}
}
return sb.toString();
}
private static String createECCBlock(CharSequence codewords, 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 = 0; i < codewords.length(); 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);
}
}

View File

@@ -0,0 +1,484 @@
/*
* 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
*/
static final String MACRO_05_HEADER = "[)>\u001E05\u001D";
/**
* 06 Macro header
*/
static final String MACRO_06_HEADER = "[)>\u001E06\u001D";
/**
* Macro trailer
*/
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() {
}
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, false);
}
/**
* 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) {
return encodeHighLevel(msg, shape, minSize, maxSize, false);
}
/**
* 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
* @param forceC40 enforce C40 encoding
* @return the encoded message (the char values range from 0 to 255)
*/
public static String encodeHighLevel(String msg,
SymbolShapeHint shape,
Dimension minSize,
Dimension maxSize,
boolean forceC40) {
//the codewords 0..255 are encoded as Unicode characters
C40Encoder c40Encoder = new C40Encoder();
Encoder[] encoders = {
new ASCIIEncoder(), 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
if (forceC40) {
c40Encoder.encodeMaximal(context);
encodingMode = context.getNewEncoding();
context.resetEncoderSignal();
}
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) {
int newMode = lookAheadTestIntern(msg, startpos, currentMode);
if (currentMode == X12_ENCODATION && newMode == X12_ENCODATION) {
int endpos = Math.min(startpos + 3, msg.length());
for (int i = startpos; i < endpos; i++) {
if (!isNativeX12(msg.charAt(i))) {
return ASCII_ENCODATION;
}
}
} else if (currentMode == EDIFACT_ENCODATION && newMode == EDIFACT_ENCODATION) {
int endpos = Math.min(startpos + 4, msg.length());
for (int i = startpos; i < endpos; i++) {
if (!isNativeEDIFACT(msg.charAt(i))) {
return ASCII_ENCODATION;
}
}
}
return newMode;
}
static int lookAheadTestIntern(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;
byte[] mins = new byte[6];
int[] intCharCounts = new int[6];
while (true) {
//step K
if ((startpos + charsProcessed) == msg.length()) {
Arrays.fill(mins, (byte) 0);
Arrays.fill(intCharCounts, 0);
int min = findMinimums(charCounts, intCharCounts, Integer.MAX_VALUE, mins);
int minCount = getMinimumCount(mins);
if (intCharCounts[ASCII_ENCODATION] == min) {
return ASCII_ENCODATION;
}
if (minCount == 1) {
if (mins[BASE256_ENCODATION] > 0) {
return BASE256_ENCODATION;
}
if (mins[EDIFACT_ENCODATION] > 0) {
return EDIFACT_ENCODATION;
}
if (mins[TEXT_ENCODATION] > 0) {
return TEXT_ENCODATION;
}
if (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) {
Arrays.fill(mins, (byte) 0);
Arrays.fill(intCharCounts, 0);
findMinimums(charCounts, intCharCounts, Integer.MAX_VALUE, mins);
if (intCharCounts[ASCII_ENCODATION] < min(intCharCounts[BASE256_ENCODATION],
intCharCounts[C40_ENCODATION], intCharCounts[TEXT_ENCODATION], intCharCounts[X12_ENCODATION],
intCharCounts[EDIFACT_ENCODATION])) {
return ASCII_ENCODATION;
}
if (intCharCounts[BASE256_ENCODATION] < intCharCounts[ASCII_ENCODATION] ||
intCharCounts[BASE256_ENCODATION] + 1 < min(intCharCounts[C40_ENCODATION],
intCharCounts[TEXT_ENCODATION], intCharCounts[X12_ENCODATION], intCharCounts[EDIFACT_ENCODATION])) {
return BASE256_ENCODATION;
}
if (intCharCounts[EDIFACT_ENCODATION] + 1 < min(intCharCounts[BASE256_ENCODATION],
intCharCounts[C40_ENCODATION] , intCharCounts[TEXT_ENCODATION] , intCharCounts[X12_ENCODATION],
intCharCounts[ASCII_ENCODATION])) {
return EDIFACT_ENCODATION;
}
if (intCharCounts[TEXT_ENCODATION] + 1 < min(intCharCounts[BASE256_ENCODATION],
intCharCounts[C40_ENCODATION] , intCharCounts[EDIFACT_ENCODATION] , intCharCounts[X12_ENCODATION],
intCharCounts[ASCII_ENCODATION])) {
return TEXT_ENCODATION;
}
if (intCharCounts[X12_ENCODATION] + 1 < min(intCharCounts[BASE256_ENCODATION],
intCharCounts[C40_ENCODATION] , intCharCounts[EDIFACT_ENCODATION] , intCharCounts[TEXT_ENCODATION],
intCharCounts[ASCII_ENCODATION])) {
return X12_ENCODATION;
}
if (intCharCounts[C40_ENCODATION] + 1 < min(intCharCounts[ASCII_ENCODATION],
intCharCounts[BASE256_ENCODATION] , intCharCounts[EDIFACT_ENCODATION] , 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 min(int f1, int f2, int f3, int f4, int f5) {
return Math.min(min(f1, f2, f3, f4),f5);
}
private static int min(int f1, int f2, int f3, int f4) {
return Math.min(f1, Math.min(f2, Math.min(f3, f4)));
}
private static int findMinimums(float[] charCounts, int[] intCharCounts, int min, byte[] mins) {
for (int i = 0; i < 6; i++) {
int current = (intCharCounts[i] = (int) Math.ceil(charCounts[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;
}
static boolean isNativeC40(char ch) {
return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z');
}
static boolean isNativeText(char ch) {
return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z');
}
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 == '>');
}
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 len = msg.length();
int idx = startpos;
while (idx < len && isDigit(msg.charAt(idx))) {
idx++;
}
return idx - startpos;
}
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 + ')');
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,236 @@
/*
* 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 {
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;
private final boolean rectangular;
private final int dataCapacity;
private final int errorCodewords;
public final int matrixWidth;
public final int matrixHeight;
private final int dataRegions;
private final int rsBlockData;
private final int rsBlockError;
/**
* 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;
}
public SymbolInfo(boolean rectangular, int dataCapacity, int errorCodewords,
int matrixWidth, int matrixHeight, int dataRegions) {
this(rectangular, dataCapacity, errorCodewords, matrixWidth, matrixHeight, dataRegions,
dataCapacity, errorCodewords);
}
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;
}
private int getHorizontalDataRegions() {
switch (dataRegions) {
case 1:
return 1;
case 2:
case 4:
return 2;
case 16:
return 4;
case 36:
return 6;
default:
throw new IllegalStateException("Cannot handle this number of data regions");
}
}
private int getVerticalDataRegions() {
switch (dataRegions) {
case 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 final int getDataCapacity() {
return dataCapacity;
}
public final int getErrorCodewords() {
return errorCodewords;
}
public int getDataLengthForInterleavedBlock(int index) {
return rsBlockData;
}
public final int getErrorLengthForInterleavedBlock(int index) {
return rsBlockError;
}
@Override
public final String toString() {
return (rectangular ? "Rectangular Symbol:" : "Square Symbol:") +
" data region " + matrixWidth + 'x' + matrixHeight +
", symbol size " + getSymbolWidth() + 'x' + getSymbolHeight() +
", symbol data size " + getSymbolDataWidth() + 'x' + getSymbolDataHeight() +
", codewords " + dataCapacity + '+' + errorCodewords;
}
}

View File

@@ -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,
}

View File

@@ -0,0 +1,81 @@
/*
* 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 < ' ') {
sb.append('\0'); //Shift 1 Set
sb.append(c);
return 2;
}
if (c <= '/') {
sb.append('\1'); //Shift 2 Set
sb.append((char) (c - 33));
return 2;
}
if (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 == '`') {
sb.append('\2'); //Shift 3 Set
sb.append((char) 0); // '`' - 96 == 0
return 2;
}
if (c <= 'Z') {
sb.append('\2'); //Shift 3 Set
sb.append((char) (c - 65 + 1));
return 2;
}
if (c <= 127) {
sb.append('\2'); //Shift 3 Set
sb.append((char) (c - 123 + 27));
return 2;
}
sb.append("\1\u001e"); //Shift 2, Upper Shift
int len = 2;
len += encodeChar((char) (c - 128), sb);
return len;
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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.getMessage(), context.pos, getEncodingMode());
if (newMode != getEncodingMode()) {
// Return to ASCII encodation, which will actually handle latch to new mode
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
break;
}
}
}
handleEOD(context, buffer);
}
@Override
int encodeChar(char c, StringBuilder sb) {
switch (c) {
case '\r':
sb.append('\0');
break;
case '*':
sb.append('\1');
break;
case '>':
sb.append('\2');
break;
case ' ':
sb.append('\3');
break;
default:
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);
}
break;
}
return 1;
}
@Override
void handleEOD(EncoderContext context, StringBuilder buffer) {
context.updateSymbolInfo();
int available = context.getSymbolInfo().getDataCapacity() - context.getCodewordCount();
int count = buffer.length();
context.pos -= count;
if (context.getRemainingCharacters() > 1 || available > 1 ||
context.getRemainingCharacters() != available) {
context.writeCodeword(HighLevelEncoder.X12_UNLATCH);
}
if (context.getNewEncoding() < 0) {
context.signalEncoderChange(HighLevelEncoder.ASCII_ENCODATION);
}
}
}