Issue 1026 PDF417 encoding improvements

git-svn-id: https://zxing.googlecode.com/svn/trunk@2006 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2011-11-02 13:57:49 +00:00
parent d148e9ff9d
commit 5d47b0f8d0
4 changed files with 83 additions and 64 deletions

View file

@ -0,0 +1,26 @@
/*
* Copyright 2011 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.pdf417.encoder;
public enum Compaction {
AUTO,
TEXT,
BYTE,
NUMERIC
}

View file

@ -510,10 +510,9 @@ final class PDF417 {
private static final float DEFAULT_MODULE_WIDTH = 0.357f; //1px in mm private static final float DEFAULT_MODULE_WIDTH = 0.357f; //1px in mm
private static final float HEIGHT = 2.0f; //mm private static final float HEIGHT = 2.0f; //mm
private int errorCorrectionLevel;
private BarcodeMatrix barcodeMatrix; private BarcodeMatrix barcodeMatrix;
private boolean compact; private boolean compact;
private boolean byteCompaction; private Compaction compaction;
private int minCols; private int minCols;
private int maxCols; private int maxCols;
private int maxRows; private int maxRows;
@ -525,6 +524,7 @@ final class PDF417 {
PDF417(boolean compact) { PDF417(boolean compact) {
this.compact = compact; this.compact = compact;
compaction = Compaction.AUTO;
minCols = 2; minCols = 2;
maxCols = 30; maxCols = 30;
maxRows = 30; maxRows = 30;
@ -639,8 +639,6 @@ final class PDF417 {
int errorCorrectionLevel, int errorCorrectionLevel,
BarcodeMatrix logic) { BarcodeMatrix logic) {
this.errorCorrectionLevel = errorCorrectionLevel;
int idx = 0; int idx = 0;
for (int y = 0; y < r; y++) { for (int y = 0; y < r; y++) {
int cluster = y % 3; int cluster = y % 3;
@ -689,10 +687,10 @@ final class PDF417 {
//1. step: High-level encoding //1. step: High-level encoding
int errorCorrectionCodeWords = PDF417ErrorCorrection.getErrorCorrectionCodewordCount(errorCorrectionLevel); int errorCorrectionCodeWords = PDF417ErrorCorrection.getErrorCorrectionCodewordCount(errorCorrectionLevel);
String highLevel = PDF417HighLevelEncoder.encodeHighLevel(msg, byteCompaction); String highLevel = PDF417HighLevelEncoder.encodeHighLevel(msg, compaction);
int sourceCodeWords = highLevel.length(); int sourceCodeWords = highLevel.length();
int[] dimension = determineDimensions(sourceCodeWords); int[] dimension = determineDimensions(sourceCodeWords, errorCorrectionCodeWords);
int cols = dimension[0]; int cols = dimension[0];
int rows = dimension[1]; int rows = dimension[1];
@ -700,12 +698,11 @@ final class PDF417 {
int pad = getNumberOfPadCodewords(sourceCodeWords, errorCorrectionCodeWords, cols, rows); int pad = getNumberOfPadCodewords(sourceCodeWords, errorCorrectionCodeWords, cols, rows);
//2. step: construct data codewords //2. step: construct data codewords
int n = getNumberOfDataCodewords(sourceCodeWords, errorCorrectionLevel, cols); if (sourceCodeWords + errorCorrectionCodeWords + 1 > 929) { // +1 for symbol length CW
if (n > 929) {
throw new WriterException( throw new WriterException(
"Encoded message contains to many code words, message to big (" + msg.length() + " bytes)"); "Encoded message contains to many code words, message to big (" + msg.length() + " bytes)");
} }
int n = sourceCodeWords + pad + 1;
StringBuilder sb = new StringBuilder(n); StringBuilder sb = new StringBuilder(n);
sb.append((char) n); sb.append((char) n);
sb.append(highLevel); sb.append(highLevel);
@ -728,13 +725,12 @@ final class PDF417 {
* codewords. * codewords.
* *
* @param sourceCodeWords number of code words * @param sourceCodeWords number of code words
* @param errorCorrectionCodeWords number of error correction code words
* @return dimension object containing cols as width and rows as height * @return dimension object containing cols as width and rows as height
*/ */
int[] determineDimensions(int sourceCodeWords) throws WriterException { int[] determineDimensions(int sourceCodeWords, int errorCorrectionCodeWords) throws WriterException {
float ratio = 0.0f; float ratio = 0.0f;
int[] dimension = null; int[] dimension = null;
int errorCorrectionCodeWords = PDF417ErrorCorrection.getErrorCorrectionCodewordCount(errorCorrectionLevel);
for (int cols = minCols; cols <= maxCols; cols++) { for (int cols = minCols; cols <= maxCols; cols++) {
@ -759,9 +755,18 @@ final class PDF417 {
dimension = new int[] {cols, rows}; dimension = new int[] {cols, rows};
} }
// Handle case when min values were larger than necessary
if (dimension == null) {
int rows = calculateNumberOfRows(sourceCodeWords, errorCorrectionCodeWords, minCols);
if (rows < minRows) {
dimension = new int[]{minCols, minRows};
}
}
if (dimension == null) { if (dimension == null) {
throw new WriterException("Unable to fit message in columns"); throw new WriterException("Unable to fit message in columns");
} }
return dimension; return dimension;
} }
@ -776,11 +781,10 @@ final class PDF417 {
} }
/** /**
* Sets byte compaction to be true or false * Sets compaction to values stored in {@link Compaction} enum
* @param byteCompaction
*/ */
void setByteCompaction(boolean byteCompaction) { void setCompaction(Compaction compaction) {
this.byteCompaction = byteCompaction; this.compaction = compaction;
} }
/** /**

View file

@ -148,7 +148,7 @@ final class PDF417HighLevelEncoder {
* @param msg the message * @param msg the message
* @return the encoded message (the char values range from 0 to 928) * @return the encoded message (the char values range from 0 to 928)
*/ */
static String encodeHighLevel(String msg, boolean byteCompaction) throws WriterException { static String encodeHighLevel(String msg, Compaction compaction) throws WriterException {
byte[] bytes = null; //Fill later and only if needed byte[] bytes = null; //Fill later and only if needed
//the codewords 0..928 are encoded as Unicode characters //the codewords 0..928 are encoded as Unicode characters
@ -159,31 +159,20 @@ final class PDF417HighLevelEncoder {
int encodingMode = TEXT_COMPACTION; //Default mode, see 4.4.2.1 int encodingMode = TEXT_COMPACTION; //Default mode, see 4.4.2.1
int textSubMode = SUBMODE_ALPHA; int textSubMode = SUBMODE_ALPHA;
if (byteCompaction) { // Can choose only byte compaction // User selected encoding mode
encodingMode = BYTE_COMPACTION; if (compaction == Compaction.TEXT) {
while (p < len) { encodeText(msg, p, len, sb, textSubMode);
if (bytes == null) { } else if (compaction == Compaction.BYTE) {
encodingMode = BYTE_COMPACTION;
bytes = getBytesForMessage(msg); bytes = getBytesForMessage(msg);
} encodeBinary(bytes, p, bytes.length, encodingMode, sb);
int b = determineConsecutiveBinaryCount(msg, bytes, p);
if (b == 0) { } else if (compaction == Compaction.NUMERIC) {
b = 1; encodingMode = NUMERIC_COMPACTION;
} sb.append((char) LATCH_TO_NUMERIC);
// I don't see how this ever takes value TEXT_COMPACTION? encodeNumeric(msg, p, len, sb);
//if (b == 1 && encodingMode == TEXT_COMPACTION) {
if (b == 1) {
//Switch for one byte (instead of latch)
encodeBinary(bytes, p, 1, TEXT_COMPACTION, sb);
} else {
//Mode latch performed by encodeBinary()
encodeBinary(bytes, p, b, encodingMode, sb);
// ... so this is redundant?
//encodingMode = BYTE_COMPACTION;
//textSubMode = SUBMODE_ALPHA; //Reset after latch
}
p += b;
}
} else { } else {
while (p < len) { while (p < len) {
int n = determineConsecutiveDigitCount(msg, p); int n = determineConsecutiveDigitCount(msg, p);
@ -373,17 +362,13 @@ final class PDF417HighLevelEncoder {
StringBuilder sb) { StringBuilder sb) {
if (count == 1 && startmode == TEXT_COMPACTION) { if (count == 1 && startmode == TEXT_COMPACTION) {
sb.append((char) SHIFT_TO_BYTE); sb.append((char) SHIFT_TO_BYTE);
} else {
boolean sixpack = (count % 6) == 0;
if (sixpack) {
sb.append((char) LATCH_TO_BYTE);
} else {
sb.append((char) LATCH_TO_BYTE_PADDED);
}
} }
char[] chars = new char[5];
int idx = startpos; int idx = startpos;
// Encode sixpacks
if (count >= 6) {
sb.append((char) LATCH_TO_BYTE);
char[] chars = new char[5];
while ((startpos + count - idx) >= 6) { while ((startpos + count - idx) >= 6) {
long t = 0; long t = 0;
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
@ -399,7 +384,11 @@ final class PDF417HighLevelEncoder {
} }
idx += 6; idx += 6;
} }
}
//Encode rest (remaining n<5 bytes if any) //Encode rest (remaining n<5 bytes if any)
if (idx < startpos + count) {
sb.append((char) LATCH_TO_BYTE_PADDED);
}
for (int i = idx; i < startpos + count; i++) { for (int i = idx; i < startpos + count; i++) {
int ch = bytes[i] & 0xff; int ch = bytes[i] & 0xff;
sb.append((char) ch); sb.append((char) ch);

View file

@ -56,12 +56,12 @@ public final class PDF417Writer implements Writer {
int maxCols, int maxCols,
int minRows, int minRows,
int maxRows, int maxRows,
boolean byteCompaction) throws WriterException { Compaction compaction) throws WriterException {
PDF417 encoder = initializeEncoder(format, compact); PDF417 encoder = initializeEncoder(format, compact);
// Set options: dimensions and byte compaction // Set options: dimensions and byte compaction
encoder.setDimensions(maxCols, minCols, maxRows, minRows); encoder.setDimensions(maxCols, minCols, maxRows, minRows);
encoder.setByteCompaction(byteCompaction); encoder.setCompaction(compaction);
return bitMatrixFromEncoder(encoder, contents, width, height); return bitMatrixFromEncoder(encoder, contents, width, height);
} }