Style changes to Aztec, enable in web app and command line

git-svn-id: https://zxing.googlecode.com/svn/trunk@1669 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2010-11-21 20:47:00 +00:00
parent e1c047c54b
commit c4dede3689
8 changed files with 871 additions and 908 deletions

View file

@ -1,32 +1,48 @@
/*
* Copyright 2010 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.aztec;
import com.google.zxing.ResultPoint;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.DetectorResult;
public class AztecDetectorResult extends DetectorResult {
public final class AztecDetectorResult extends DetectorResult {
private final boolean compact;
private final int nbDatablocks;
private final int nbLayers;
public AztecDetectorResult(BitMatrix bits, ResultPoint[] points, boolean compact, int nbDatablocks, int nbLayers) {
super(bits, points);
this.compact = compact;
this.nbDatablocks = nbDatablocks;
this.nbLayers = nbLayers;
}
private final boolean compact;
private final int nbDatablocks;
private final int nbLayers;
public int getNbLayers() {
return nbLayers;
}
public AztecDetectorResult(BitMatrix bits, ResultPoint[] points, boolean compact, int nbDatablocks, int nbLayers) {
super(bits, points);
this.compact = compact;
this.nbDatablocks = nbDatablocks;
this.nbLayers = nbLayers;
}
public int getNbDatablocks() {
return nbDatablocks;
}
public int getNbLayers() {
return nbLayers;
}
public boolean isCompact() {
return compact;
}
public int getNbDatablocks() {
return nbDatablocks;
}
public boolean isCompact() {
return compact;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2007 ZXing authors
* Copyright 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -28,7 +28,6 @@ import com.google.zxing.ResultMetadataType;
import com.google.zxing.ResultPoint;
import com.google.zxing.ResultPointCallback;
import com.google.zxing.common.DecoderResult;
import com.google.zxing.common.DetectorResult;
import com.google.zxing.aztec.decoder.Decoder;
import com.google.zxing.aztec.detector.Detector;
@ -41,8 +40,6 @@ import java.util.Hashtable;
*/
public final class AztecReader implements Reader {
private static final ResultPoint[] NO_POINTS = new ResultPoint[0];
/**
* Locates and decodes a Data Matrix code in an image.
*
@ -51,28 +48,26 @@ public final class AztecReader implements Reader {
* @throws FormatException if a Data Matrix code cannot be decoded
* @throws ChecksumException if error correction fails
*/
public Result decode(BinaryBitmap image) throws NotFoundException, ChecksumException, FormatException {
public Result decode(BinaryBitmap image) throws NotFoundException, FormatException {
return decode(image, null);
}
public Result decode(BinaryBitmap image, Hashtable hints)
throws NotFoundException, ChecksumException, FormatException {
DecoderResult decoderResult;
ResultPoint[] points;
throws NotFoundException, FormatException {
AztecDetectorResult detectorResult = new Detector(image.getBlackMatrix()).detect();
points = detectorResult.getPoints();
ResultPoint[] points = detectorResult.getPoints();
if (hints != null && detectorResult.getPoints() != null){
ResultPointCallback rpcb = (ResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
if (rpcb != null){
for (int i = 0; i < detectorResult.getPoints().length; i++){
rpcb.foundPossibleResultPoint(detectorResult.getPoints()[i]);
}
}
if (hints != null && detectorResult.getPoints() != null) {
ResultPointCallback rpcb = (ResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
if (rpcb != null) {
for (int i = 0; i < detectorResult.getPoints().length; i++) {
rpcb.foundPossibleResultPoint(detectorResult.getPoints()[i]);
}
}
}
decoderResult = new Decoder().decode(detectorResult);
DecoderResult decoderResult = new Decoder().decode(detectorResult);
Result result = new Result(decoderResult.getText(), decoderResult.getRawBytes(), points, BarcodeFormat.AZTEC);

View file

@ -1,5 +1,5 @@
/*
* Copyright 2007 ZXing authors
* Copyright 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,7 +16,6 @@
package com.google.zxing.aztec.decoder;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.aztec.AztecDetectorResult;
import com.google.zxing.common.BitMatrix;
@ -33,435 +32,421 @@ import com.google.zxing.common.reedsolomon.ReedSolomonException;
*/
public final class Decoder {
int numCodewords;
int codewordSize;
AztecDetectorResult ddata;
public Decoder() {}
private static final int UPPER = 0;
private static final int LOWER = 1;
private static final int MIXED = 2;
private static final int DIGIT = 3;
private static final int PUNCT = 4;
private static final int BINARY = 5;
public DecoderResult decode(AztecDetectorResult detectorResult) throws FormatException, ChecksumException {
ddata = detectorResult;
BitMatrix matrix = detectorResult.getBits();
if (!ddata.isCompact()){
matrix = removeDashedLines(ddata.getBits());
}
boolean[] rawbits = extractBits(matrix);
boolean[] correctedBits = correctBits(rawbits);
String result = getEncodedData(correctedBits);
return new DecoderResult(null, result, null, null);
private static final int[] NB_BITS_COMPACT = {
0, 104, 240, 408, 608
};
private static final int[] NB_BITS = {
0, 128, 288, 480, 704, 960, 1248, 1568, 1920, 2304, 2720, 3168, 3648, 4160, 4704, 5280, 5888, 6528,
7200, 7904, 8640, 9408, 10208, 11040, 11904, 12800, 13728, 14688, 15680, 16704, 17760, 18848, 19968
};
private static final int[] NB_DATABLOCK_COMPACT = {
0, 17, 40, 51, 76
};
private static final int[] NB_DATABLOCK = {
0, 21, 48, 60, 88, 120, 156, 196, 240, 230, 272, 316, 364, 416, 470, 528, 588, 652, 720, 790, 864,
940, 1020, 920, 992, 1066, 1144, 1224, 1306, 1392, 1480, 1570, 1664
};
private static final String[] UPPER_TABLE = {
"CTRL_PS", " ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "CTRL_LL", "CTRL_ML", "CTRL_DL", "CTRL_BS"
};
private static final String[] LOWER_TABLE = {
"CTRL_PS", " ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
"q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "CTRL_US", "CTRL_ML", "CTRL_DL", "CTRL_BS"
};
private static final String[] MIXED_TABLE = {
"CTRL_PS", " ", "\1", "\2", "\3", "\4", "\5", "\6", "\7", "\b", "\t", "\n",
"\13", "\f", "\r", "\33", "\34", "\35", "\36", "\37", "@", "\\", "^", "_",
"`", "|", "~", "\177", "CTRL_LL", "CTRL_UL", "CTRL_PL", "CTRL_BS"
};
private static final String[] PUNCT_TABLE = {
"", "\r", "\r\n", ". ", ", ", ": ", "!", "\"", "#", "$", "%", "&", "'", "(", ")",
"*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", "CTRL_UL"
};
private static final String[] DIGIT_TABLE = {
"CTRL_PS", " ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "CTRL_UL", "CTRL_US"
};
private int numCodewords;
private int codewordSize;
private AztecDetectorResult ddata;
public DecoderResult decode(AztecDetectorResult detectorResult) throws FormatException {
ddata = detectorResult;
BitMatrix matrix = detectorResult.getBits();
if (!ddata.isCompact()) {
matrix = removeDashedLines(ddata.getBits());
}
boolean[] rawbits = extractBits(matrix);
boolean[] correctedBits = correctBits(rawbits);
String result = getEncodedData(correctedBits);
return new DecoderResult(null, result, null, null);
}
/**
*
* Gets the string encoded in the aztec code bits
*
* @param correctedBits
* @return the decoded string
* @throws FormatException if the input is not valid
*/
private String getEncodedData(boolean[] correctedBits) throws FormatException {
int endIndex = codewordSize * ddata.getNbDatablocks();
if (endIndex > correctedBits.length){
throw FormatException.getFormatInstance();
}
int lastTable = UPPER;
int table = UPPER;
int startIndex = 0;
int code;
StringBuilder result = new StringBuilder();
boolean end = false;
boolean shift = false;
boolean switchShift = false;
while (!end){
if (shift){
// the table is for the next character only
switchShift = true;
} else {
// save the current table in case next one is a shift
lastTable = table;
}
switch (table) {
case BINARY:
if (endIndex - startIndex < 8){
end = true;
break;
}
code = readCode(correctedBits, startIndex, 8);
startIndex += 8;
result.append((char)(code));
break;
default:
int size = 5;
if (table == DIGIT){
size = 4;
}
if (endIndex - startIndex < size){
end = true;
break;
}
code = readCode(correctedBits, startIndex, size);
startIndex += size;
String str = getCharacter(table, code);
if (!str.startsWith("CTRL_")){
result.append(str);
} else {
// Table changes
table = getTable(str.charAt(5));
if (str.charAt(6) == 'S'){
shift = true;
}
}
break;
}
if (switchShift){
table = lastTable;
shift = false;
switchShift = false;
}
}
return result.toString();
}
/**
*
* gets the table corresponding to the char passed
*
* @param t
* @return
*/
private int getTable(char t) {
int table = UPPER;
switch (t){
case 'U':
table = UPPER; break;
case 'L':
table = LOWER; break;
case 'P':
table = PUNCT; break;
case 'M':
table = MIXED; break;
case 'D':
table = DIGIT; break;
case 'B':
table = BINARY; break;
}
return table;
}
/**
*
* Gets the character (or string) corresponding to the passed code in the given table
*
* @param table the table used
* @param code the code of the character
* @return
*/
private String getCharacter(int table, int code) {
switch (table){
case UPPER:
return UPPER_TABLE[code];
case LOWER:
return LOWER_TABLE[code];
case MIXED:
return MIXED_TABLE[code];
case PUNCT:
return PUNCT_TABLE[code];
case DIGIT:
return DIGIT_TABLE[code];
default:
return "";
}
}
/**
*
* <p> performs RS error correction on an array of bits </p>
*
* @param rawbits
* @return the corrected array
* @throws FormatException if the input contains too many errors
*/
private boolean[] correctBits(boolean[] rawbits) throws FormatException {
GenericGF gf;
if (ddata.getNbLayers() <= 2){
codewordSize = 6;
gf = GenericGF.AZTEC_DATA_6;
} else if (ddata.getNbLayers() <= 8) {
codewordSize = 8;
gf = GenericGF.AZTEC_DATA_8;
} else if (ddata.getNbLayers() <= 22) {
codewordSize = 10;
gf = GenericGF.AZTEC_DATA_10;
} else {
codewordSize = 12;
gf = GenericGF.AZTEC_DATA_12;
}
int numDataCodewords = ddata.getNbDatablocks();
int numECCodewords = 0;
int offset = 0;
if (ddata.isCompact()){
offset = NbBitsCompact[ddata.getNbLayers()] - numCodewords*codewordSize;
numECCodewords = NbDatablockCompact[ddata.getNbLayers()] - numDataCodewords;
} else {
offset = NbBits[ddata.getNbLayers()] - numCodewords*codewordSize;
numECCodewords = NbDatablock[ddata.getNbLayers()] - numDataCodewords;
}
int[] dataWords = new int[numCodewords];
for (int i = 0; i < numCodewords; i++){
int flag = 1;
for (int j = 1; j <= codewordSize; j++){
if (rawbits[codewordSize*i + codewordSize - j + offset]){
dataWords[i] += flag;
}
flag <<= 1;
}
if (dataWords[i] >= flag){
flag++;
}
}
rawbits = null;
try {
ReedSolomonDecoder rsDecoder = new ReedSolomonDecoder(gf);
rsDecoder.decode(dataWords, numECCodewords);
} catch (ReedSolomonException rse) {
System.out.println("END: invalid RS");
throw FormatException.getFormatInstance();
}
offset = 0;
boolean[] correctedBits = new boolean[numDataCodewords*codewordSize];
for (int i = 0; i < numDataCodewords; i ++){
boolean seriesColor = false;
int seriesCount = 0;
int flag = 1 << (codewordSize - 1);
for (int j = 0; j < codewordSize; j++){
boolean color = (dataWords[i] & flag) == flag;
if (seriesCount != codewordSize - 1){
if (seriesColor == color){
seriesCount++;
} else {
seriesCount = 1;
seriesColor = color;
}
correctedBits[i*codewordSize+j-offset] = color;
} else {
if (color == seriesColor){
//bit must be inverted
throw FormatException.getFormatInstance();
}
seriesColor = false;
seriesCount = 0;
offset++;
}
flag >>>= 1;
}
}
return correctedBits;
}
/**
*
* Gets the array of bits from an Aztec Code matrix
*
* @param matrix
* @return the array of bits
* @throws FormatException if the matrix is not a valid aztec code
*/
private boolean[] extractBits(BitMatrix matrix) throws FormatException {
boolean[] rawbits;
if (ddata.isCompact()){
if (ddata.getNbLayers() > NbBitsCompact.length){
throw FormatException.getFormatInstance();
}
rawbits = new boolean[NbBitsCompact[ddata.getNbLayers()]];
numCodewords = NbDatablockCompact[ddata.getNbLayers()];
} else {
if (ddata.getNbLayers() > NbBits.length){
throw FormatException.getFormatInstance();
}
rawbits = new boolean[NbBits[ddata.getNbLayers()]];
numCodewords = NbDatablock[ddata.getNbLayers()];
}
int flip;
int layer = ddata.getNbLayers();
int size = matrix.height;
int rawbitsOffset = 0;
int matrixOffset = 0;
while (layer != 0){
flip = 0;
for (int i = 0; i < 2*size - 4; i++){
rawbits[rawbitsOffset+i] = matrix.get(matrixOffset + flip, matrixOffset + i/2);
rawbits[rawbitsOffset+2*size - 4 + i] = matrix.get(matrixOffset + i/2, matrixOffset + size-1-flip);
flip = (flip + 1)%2;
}
flip = 0;
for (int i = 2*size+1; i > 5; i--){
rawbits[rawbitsOffset+4*size - 8 + (2*size-i) + 1] = matrix.get(matrixOffset + size-1-flip, matrixOffset + i/2 - 1);
rawbits[rawbitsOffset+6*size - 12 + (2*size-i) + 1] = matrix.get(matrixOffset + i/2 - 1, matrixOffset + flip);
flip = (flip + 1)%2;
}
matrixOffset += 2;
rawbitsOffset += 8*size-16;
layer--;
size-=4;
}
return rawbits;
}
/**
*
* <p> Transforms an aztec code matrix by removing the control dashed lines </p>
*
* @param matrix
* @return
*
* Gets the string encoded in the aztec code bits
*
* @return the decoded string
* @throws FormatException if the input is not valid
*/
private BitMatrix removeDashedLines(BitMatrix matrix) {
int nbDashed = 1+ 2* ((matrix.width - 1)/2 / 16);
BitMatrix newMatrix = new BitMatrix(matrix.width - nbDashed, matrix.height - nbDashed);
int nx = 0;
int ny = 0;
for (int x = 0; x < matrix.width; x++){
ny = 0;
if ((matrix.width / 2 - x)%16 == 0){
continue;
}
for (int y = 0; y < matrix.height; y++){
if ((matrix.width / 2 - y)%16 == 0){
continue;
}
if (matrix.get(x, y)){
newMatrix.set(nx, ny);
}
ny++;
}
nx++;
}
return newMatrix;
}
private String getEncodedData(boolean[] correctedBits) throws FormatException {
/**
*
* Reads a code of given length and at given index in an array of bits
*
* @param rawbits
* @param startIndex
* @param length
* @return
*/
private int readCode(boolean[] rawbits, int startIndex, int length) {
int res = 0;
for (int i = startIndex; i < startIndex + length; i++){
res = res << 1;
if (rawbits[i]){
res++;
}
}
return res;
}
int endIndex = codewordSize * ddata.getNbDatablocks();
if (endIndex > correctedBits.length) {
throw FormatException.getFormatInstance();
}
static final int UPPER = 0;
static final int LOWER = 1;
static final int MIXED = 2;
static final int DIGIT = 3;
static final int PUNCT = 4;
static final int BINARY = 5;
int lastTable = UPPER;
int table = UPPER;
int startIndex = 0;
StringBuilder result = new StringBuilder(20);
boolean end = false;
boolean shift = false;
boolean switchShift = false;
static final int NbBitsCompact[] = {
0,104, 240, 408, 608
};
while (!end) {
if (shift) {
// the table is for the next character only
switchShift = true;
} else {
// save the current table in case next one is a shift
lastTable = table;
}
int code;
switch (table) {
case BINARY:
if (endIndex - startIndex < 8) {
end = true;
break;
}
code = readCode(correctedBits, startIndex, 8);
startIndex += 8;
result.append((char)(code));
break;
default:
int size = 5;
if (table == DIGIT) {
size = 4;
}
if (endIndex - startIndex < size) {
end = true;
break;
}
code = readCode(correctedBits, startIndex, size);
startIndex += size;
String str = getCharacter(table, code);
if (str.startsWith("CTRL_")) {
// Table changes
table = getTable(str.charAt(5));
if (str.charAt(6) == 'S') {
shift = true;
}
} else {
result.append(str);
}
break;
}
if (switchShift) {
table = lastTable;
shift = false;
switchShift = false;
}
}
return result.toString();
}
/**
* gets the table corresponding to the char passed
*/
private static int getTable(char t) {
int table = UPPER;
switch (t) {
case 'U':
table = UPPER;
break;
case 'L':
table = LOWER;
break;
case 'P':
table = PUNCT;
break;
case 'M':
table = MIXED;
break;
case 'D':
table = DIGIT;
break;
case 'B':
table = BINARY;
break;
}
return table;
}
static final int NbBits[] = {
0, 128, 288, 480, 704, 960, 1248, 1568, 1920, 2304, 2720, 3168, 3648, 4160, 4704, 5280, 5888, 6528, 7200, 7904, 8640, 9408, 10208, 11040, 11904, 12800, 13728, 14688, 15680, 16704, 17760, 18848, 19968
};
/**
*
* Gets the character (or string) corresponding to the passed code in the given table
*
* @param table the table used
* @param code the code of the character
*/
private static String getCharacter(int table, int code) {
switch (table) {
case UPPER:
return UPPER_TABLE[code];
case LOWER:
return LOWER_TABLE[code];
case MIXED:
return MIXED_TABLE[code];
case PUNCT:
return PUNCT_TABLE[code];
case DIGIT:
return DIGIT_TABLE[code];
default:
return "";
}
}
/**
*
* <p> performs RS error correction on an array of bits </p>
*
* @return the corrected array
* @throws FormatException if the input contains too many errors
*/
private boolean[] correctBits(boolean[] rawbits) throws FormatException {
GenericGF gf;
if (ddata.getNbLayers() <= 2) {
codewordSize = 6;
gf = GenericGF.AZTEC_DATA_6;
} else if (ddata.getNbLayers() <= 8) {
codewordSize = 8;
gf = GenericGF.AZTEC_DATA_8;
} else if (ddata.getNbLayers() <= 22) {
codewordSize = 10;
gf = GenericGF.AZTEC_DATA_10;
} else {
codewordSize = 12;
gf = GenericGF.AZTEC_DATA_12;
}
int numDataCodewords = ddata.getNbDatablocks();
int numECCodewords;
int offset;
if (ddata.isCompact()) {
offset = NB_BITS_COMPACT[ddata.getNbLayers()] - numCodewords*codewordSize;
numECCodewords = NB_DATABLOCK_COMPACT[ddata.getNbLayers()] - numDataCodewords;
} else {
offset = NB_BITS[ddata.getNbLayers()] - numCodewords*codewordSize;
numECCodewords = NB_DATABLOCK[ddata.getNbLayers()] - numDataCodewords;
}
int[] dataWords = new int[numCodewords];
for (int i = 0; i < numCodewords; i++) {
int flag = 1;
for (int j = 1; j <= codewordSize; j++) {
if (rawbits[codewordSize*i + codewordSize - j + offset]) {
dataWords[i] += flag;
}
flag <<= 1;
}
//if (dataWords[i] >= flag) {
// flag++;
//}
}
try {
ReedSolomonDecoder rsDecoder = new ReedSolomonDecoder(gf);
rsDecoder.decode(dataWords, numECCodewords);
} catch (ReedSolomonException rse) {
throw FormatException.getFormatInstance();
}
offset = 0;
boolean[] correctedBits = new boolean[numDataCodewords*codewordSize];
for (int i = 0; i < numDataCodewords; i ++) {
boolean seriesColor = false;
int seriesCount = 0;
int flag = 1 << (codewordSize - 1);
for (int j = 0; j < codewordSize; j++) {
boolean color = (dataWords[i] & flag) == flag;
if (seriesCount == codewordSize - 1) {
if (color == seriesColor) {
//bit must be inverted
throw FormatException.getFormatInstance();
}
seriesColor = false;
seriesCount = 0;
offset++;
} else {
if (seriesColor == color) {
seriesCount++;
} else {
seriesCount = 1;
seriesColor = color;
}
correctedBits[i * codewordSize + j - offset] = color;
}
flag >>>= 1;
}
}
return correctedBits;
}
/**
*
* Gets the array of bits from an Aztec Code matrix
*
* @return the array of bits
* @throws FormatException if the matrix is not a valid aztec code
*/
private boolean[] extractBits(BitMatrix matrix) throws FormatException {
boolean[] rawbits;
if (ddata.isCompact()) {
if (ddata.getNbLayers() > NB_BITS_COMPACT.length) {
throw FormatException.getFormatInstance();
}
rawbits = new boolean[NB_BITS_COMPACT[ddata.getNbLayers()]];
numCodewords = NB_DATABLOCK_COMPACT[ddata.getNbLayers()];
} else {
if (ddata.getNbLayers() > NB_BITS.length) {
throw FormatException.getFormatInstance();
}
rawbits = new boolean[NB_BITS[ddata.getNbLayers()]];
numCodewords = NB_DATABLOCK[ddata.getNbLayers()];
}
int layer = ddata.getNbLayers();
int size = matrix.height;
int rawbitsOffset = 0;
int matrixOffset = 0;
while (layer != 0) {
int flip = 0;
for (int i = 0; i < 2*size - 4; i++) {
rawbits[rawbitsOffset+i] = matrix.get(matrixOffset + flip, matrixOffset + i/2);
rawbits[rawbitsOffset+2*size - 4 + i] = matrix.get(matrixOffset + i/2, matrixOffset + size-1-flip);
flip = (flip + 1)%2;
}
flip = 0;
for (int i = 2*size+1; i > 5; i--) {
rawbits[rawbitsOffset+4*size - 8 + (2*size-i) + 1] = matrix.get(matrixOffset + size-1-flip, matrixOffset + i/2 - 1);
rawbits[rawbitsOffset+6*size - 12 + (2*size-i) + 1] = matrix.get(matrixOffset + i/2 - 1, matrixOffset + flip);
flip = (flip + 1)%2;
}
matrixOffset += 2;
rawbitsOffset += 8*size-16;
layer--;
size -= 4;
}
return rawbits;
}
static final int NbDatablockCompact[] = {
0, 17, 40, 51, 76
};
static final int NbDatablock[] = {
0, 21, 48, 60, 88, 120, 156, 196, 240, 230, 272, 316, 364, 416, 470, 528, 588, 652, 720, 790, 864, 940, 1020, 920, 992, 1066, 1144, 1224, 1306, 1392, 1480, 1570, 1664
};
static final String UPPER_TABLE[] = {
"CTRL_PS", " ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "CTRL_LL", "CTRL_ML", "CTRL_DL", "CTRL_BS"
};
static final String LOWER_TABLE[] = {
"CTRL_PS", " ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "CTRL_US", "CTRL_ML", "CTRL_DL", "CTRL_BS"
};
static final String MIXED_TABLE[] = {
"CTRL_PS", " ", ""+(char)1, ""+(char)2, ""+(char)3, ""+(char)4, ""+(char)5, ""+(char)6, ""+(char)7, ""+(char)8, ""+(char)9, ""+(char)10, ""+(char)11, ""+(char)12, ""+(char)13, ""+(char)27, ""+(char)28, ""+(char)29, ""+(char)30, ""+(char)31, "@", "\\", "^", ""+(char)95, "`", "|", "~", ""+(char)127, "CTRL_LL", "CTRL_UL", "CTRL_PL", "CTRL_BS"
};
static final String PUNCT_TABLE[] = {
"", ""+(char)13, ""+(char)13+(char)10, ""+(char)46+(char)32, ""+(char)44+(char)32, ""+(char)58+(char)32, "!", "\"", "#", "$", "%", "&", "'", "(", ")", ""+(char)42, "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", "CTRL_UL"
};
static final String DIGIT_TABLE[] = {
"CTRL_PS", " ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "CTRL_UL", "CTRL_US"
};
/**
* Transforms an Aztec code matrix by removing the control dashed lines
*/
private static BitMatrix removeDashedLines(BitMatrix matrix) {
int nbDashed = 1+ 2* ((matrix.width - 1)/2 / 16);
BitMatrix newMatrix = new BitMatrix(matrix.width - nbDashed, matrix.height - nbDashed);
int nx = 0;
for (int x = 0; x < matrix.width; x++) {
if ((matrix.width / 2 - x)%16 == 0) {
continue;
}
int ny = 0;
for (int y = 0; y < matrix.height; y++) {
if ((matrix.width / 2 - y)%16 == 0) {
continue;
}
if (matrix.get(x, y)) {
newMatrix.set(nx, ny);
}
ny++;
}
nx++;
}
return newMatrix;
}
/**
* Reads a code of given length and at given index in an array of bits
*/
private static int readCode(boolean[] rawbits, int startIndex, int length) {
int res = 0;
for (int i = startIndex; i < startIndex + length; i++) {
res <<= 1;
if (rawbits[i]) {
res++;
}
}
return res;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2008 ZXing authors
* Copyright 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -39,8 +39,8 @@ public final class Detector {
private boolean compact;
private int nbLayers;
private int nbDataBlocks;
private int nbCenterLayers;
private int shift;
private int nbCenterLayers;
private int shift;
public Detector(BitMatrix image) {
this.image = image;
@ -53,14 +53,14 @@ public final class Detector {
* @throws NotFoundException if no Aztec Code can be found
*/
public AztecDetectorResult detect() throws NotFoundException {
// 1. Get the center of the aztec matrix
Point pCenter = getMatrixCenter();
// 2. Get the corners of the center bull's eye
Point[] bullEyeCornerPoints = getBullEyeCornerPoints(pCenter);
// 3. Get the size of the matrix from the bull's eye
// 1. Get the center of the aztec matrix
Point pCenter = getMatrixCenter();
// 2. Get the corners of the center bull's eye
Point[] bullEyeCornerPoints = getBullEyeCornerPoints(pCenter);
// 3. Get the size of the matrix from the bull's eye
extractParameters(bullEyeCornerPoints);
// 4. Get the corners of the matrix
@ -72,75 +72,74 @@ public final class Detector {
return new AztecDetectorResult(bits, corners, compact, nbDataBlocks, nbLayers);
}
/**
* <p> Extracts the number of data layers and data blocks from the layer around the bull's eye </p>
*
* @param bullEyeCornerPoints the array of bull's eye corners
* @throws NotFoundException in case of too many errors or invalid parameters
*/
private void extractParameters(Point[] bullEyeCornerPoints)
throws NotFoundException {
// Get the bits around the bull's eye
boolean[] resab = sampleLine(bullEyeCornerPoints[0], bullEyeCornerPoints[1], 2*nbCenterLayers+1);
/**
* <p> Extracts the number of data layers and data blocks from the layer around the bull's eye </p>
*
* @param bullEyeCornerPoints the array of bull's eye corners
* @throws NotFoundException in case of too many errors or invalid parameters
*/
private void extractParameters(Point[] bullEyeCornerPoints)
throws NotFoundException {
// Get the bits around the bull's eye
boolean[] resab = sampleLine(bullEyeCornerPoints[0], bullEyeCornerPoints[1], 2*nbCenterLayers+1);
boolean[] resbc = sampleLine(bullEyeCornerPoints[1], bullEyeCornerPoints[2], 2*nbCenterLayers+1);
boolean[] rescd = sampleLine(bullEyeCornerPoints[2], bullEyeCornerPoints[3], 2*nbCenterLayers+1);
boolean[] resda = sampleLine(bullEyeCornerPoints[3], bullEyeCornerPoints[0], 2*nbCenterLayers+1);
boolean[] shiftedParameterData;
boolean[] parameterData;
// Determine the orientation of the matrix
if (resab[0]==true && resab[2*nbCenterLayers]==true){
shift = 0;
} else if (resbc[0]==true && resbc[2*nbCenterLayers]==true){
shift = 1;
} else if (rescd[0]==true && rescd[2*nbCenterLayers]==true){
shift = 2;
} else if (resda[0]==true && resda[2*nbCenterLayers]==true){
shift = 3;
if (resab[0] && resab[2 * nbCenterLayers]) {
shift = 0;
} else if (resbc[0] && resbc[2 * nbCenterLayers]) {
shift = 1;
} else if (rescd[0] && rescd[2 * nbCenterLayers]) {
shift = 2;
} else if (resda[0] && resda[2 * nbCenterLayers]) {
shift = 3;
} else {
throw NotFoundException.getNotFoundInstance();
throw NotFoundException.getNotFoundInstance();
}
//d a
//
//c b
//d a
//
//c b
// Flatten the bits in a single array
if (compact){
shiftedParameterData = new boolean[28];
for (int i = 0; i < 7; i++){
shiftedParameterData[i] = resab[2+i];
shiftedParameterData[i+7] = resbc[2+i];
shiftedParameterData[i+14] = rescd[2+i];
shiftedParameterData[i+21] = resda[2+i];
}
boolean[] parameterData;
boolean[] shiftedParameterData;
if (compact) {
shiftedParameterData = new boolean[28];
for (int i = 0; i < 7; i++) {
shiftedParameterData[i] = resab[2+i];
shiftedParameterData[i+7] = resbc[2+i];
shiftedParameterData[i+14] = rescd[2+i];
shiftedParameterData[i+21] = resda[2+i];
}
parameterData = new boolean[28];
for (int i = 0; i < 28; i++){
parameterData[i] = shiftedParameterData[(i+shift*7)%28];
parameterData = new boolean[28];
for (int i = 0; i < 28; i++) {
parameterData[i] = shiftedParameterData[(i+shift*7)%28];
}
} else {
shiftedParameterData = new boolean[40];
for (int i = 0; i < 11; i++){
if (i < 5){
shiftedParameterData[i] = resab[2+i];
shiftedParameterData[i+10] = resbc[2+i];
shiftedParameterData[i+20] = rescd[2+i];
shiftedParameterData[i+30] = resda[2+i];
}
if (i > 5){
shiftedParameterData[i-1] = resab[2+i];
shiftedParameterData[i+10-1] = resbc[2+i];
shiftedParameterData[i+20-1] = rescd[2+i];
shiftedParameterData[i+30-1] = resda[2+i];
}
}
shiftedParameterData = new boolean[40];
for (int i = 0; i < 11; i++) {
if (i < 5) {
shiftedParameterData[i] = resab[2+i];
shiftedParameterData[i+10] = resbc[2+i];
shiftedParameterData[i+20] = rescd[2+i];
shiftedParameterData[i+30] = resda[2+i];
}
if (i > 5) {
shiftedParameterData[i-1] = resab[2+i];
shiftedParameterData[i+10-1] = resbc[2+i];
shiftedParameterData[i+20-1] = rescd[2+i];
shiftedParameterData[i+30-1] = resda[2+i];
}
}
parameterData = new boolean[40];
for (int i = 0; i < 40; i++){
parameterData[i] = shiftedParameterData[(i+shift*10)%40];
parameterData = new boolean[40];
for (int i = 0; i < 40; i++) {
parameterData[i] = shiftedParameterData[(i+shift*10)%40];
}
}
@ -149,20 +148,20 @@ public final class Detector {
// gets the parameters from the bit array
getParameters(parameterData);
}
}
/**
*
* <p> Gets the aztec code corners from the bull's eye corners and the parameters </p>
*
* @param bullEyeCornerPoints the array of bull's eye corners
* @return the array of aztec code corners
* @throws NotFoundException if the corner points do not fit in the image
*/
private ResultPoint[] getMatrixCornerPoints(Point[] bullEyeCornerPoints) throws NotFoundException {
/**
*
* <p> Gets the aztec code corners from the bull's eye corners and the parameters </p>
*
* @param bullEyeCornerPoints the array of bull's eye corners
* @return the array of aztec code corners
* @throws NotFoundException if the corner points do not fit in the image
*/
private ResultPoint[] getMatrixCornerPoints(Point[] bullEyeCornerPoints) throws NotFoundException {
float ratio = (2*nbLayers+(nbLayers>4?1:0)+(nbLayers-4)/8)/(2.0f*nbCenterLayers);
int dx = bullEyeCornerPoints[0].x-bullEyeCornerPoints[2].x;
dx+=dx>0?1:-1;
int dy = bullEyeCornerPoints[0].y-bullEyeCornerPoints[2].y;
@ -184,63 +183,63 @@ public final class Detector {
int targetbx = round(bullEyeCornerPoints[1].x+ratio*dx);
int targetby = round(bullEyeCornerPoints[1].y+ratio*dy);
if (!isValid(targetax, targetay) || !isValid(targetbx, targetby) || !isValid(targetcx, targetcy) || !isValid(targetdx, targetdy)){
throw NotFoundException.getNotFoundInstance();
if (!isValid(targetax, targetay) || !isValid(targetbx, targetby) || !isValid(targetcx, targetcy) || !isValid(targetdx, targetdy)) {
throw NotFoundException.getNotFoundInstance();
}
return new ResultPoint[]{new ResultPoint(targetax, targetay), new ResultPoint(targetbx, targetby), new ResultPoint(targetcx, targetcy), new ResultPoint(targetdx, targetdy)};
}
}
/**
*
* <p> Corrects the parameter bits using Reed-Solomon algorithm </p>
*
* @param parameterData paremeter bits
* @param compact true if this is a compact Aztec code
* @throws NotFoundException if the array contains too many errors
*/
private static void correctParameterData(boolean[] parameterData, boolean compact) throws NotFoundException {
/**
*
* <p> Corrects the parameter bits using Reed-Solomon algorithm </p>
*
* @param parameterData paremeter bits
* @param compact true if this is a compact Aztec code
* @throws NotFoundException if the array contains too many errors
*/
private void correctParameterData(boolean[] parameterData, boolean compact) throws NotFoundException {
int numCodewords;
int numDataCodewords;
int codewordSize = 4;
if (compact){
if (compact) {
numCodewords = 7;
numDataCodewords = 2;
} else {
numCodewords = 10;
numDataCodewords = 4;
}
int numECCodewords = numCodewords - numDataCodewords;
int numECCodewords = numCodewords - numDataCodewords;
int[] parameterWords = new int[numCodewords];
for (int i = 0; i < numCodewords; i++){
int flag = 1;
for (int j = 1; j <= codewordSize; j++){
if (parameterData[codewordSize*i + codewordSize - j]){
parameterWords[i] += flag;
}
flag <<= 1;
}
int codewordSize = 4;
for (int i = 0; i < numCodewords; i++) {
int flag = 1;
for (int j = 1; j <= codewordSize; j++) {
if (parameterData[codewordSize*i + codewordSize - j]) {
parameterWords[i] += flag;
}
flag <<= 1;
}
}
try {
ReedSolomonDecoder rsDecoder = new ReedSolomonDecoder(GenericGF.AZTEC_PARAM);
rsDecoder.decode(parameterWords, numECCodewords);
rsDecoder.decode(parameterWords, numECCodewords);
} catch (ReedSolomonException rse) {
throw NotFoundException.getNotFoundInstance();
throw NotFoundException.getNotFoundInstance();
}
for (int i = 0; i < numDataCodewords; i ++){
int flag = 1;
for (int j = 1; j <= codewordSize; j++){
parameterData[i*codewordSize+codewordSize-j] = (parameterWords[i] & flag) == flag;
flag <<= 1;
}
for (int i = 0; i < numDataCodewords; i ++) {
int flag = 1;
for (int j = 1; j <= codewordSize; j++) {
parameterData[i*codewordSize+codewordSize-j] = (parameterWords[i] & flag) == flag;
flag <<= 1;
}
}
}
}
/**
*
@ -256,40 +255,36 @@ public final class Detector {
Point pinb = pCenter;
Point pinc = pCenter;
Point pind = pCenter;
Point pouta;
Point poutb;
Point poutc;
Point poutd;
boolean color = true;
for (nbCenterLayers = 1; nbCenterLayers < 9; nbCenterLayers++){
pouta = getFirstDifferent(pina, color, 1, -1);
poutb = getFirstDifferent(pinb, color, 1, 1);
poutc = getFirstDifferent(pinc, color, -1, 1);
poutd = getFirstDifferent(pind, color, -1, -1);
//d a
//
//c b
if (nbCenterLayers>2){
float q = (float)distance(poutd, pouta)*nbCenterLayers/(distance(pind, pina)*(nbCenterLayers+2));
if ( q < 0.75 || q > 1.25 || !isWhiteOrBlackRectangle(pouta, poutb, poutc, poutd)){
break;
}
}
pina = pouta;
pinb = poutb;
pinc = poutc;
pind = poutd;
color = !color;
for (nbCenterLayers = 1; nbCenterLayers < 9; nbCenterLayers++) {
Point pouta = getFirstDifferent(pina, color, 1, -1);
Point poutb = getFirstDifferent(pinb, color, 1, 1);
Point poutc = getFirstDifferent(pinc, color, -1, 1);
Point poutd = getFirstDifferent(pind, color, -1, -1);
//d a
//
//c b
if (nbCenterLayers>2) {
float q = distance(poutd, pouta)*nbCenterLayers/(distance(pind, pina)*(nbCenterLayers+2));
if ( q < 0.75 || q > 1.25 || !isWhiteOrBlackRectangle(pouta, poutb, poutc, poutd)) {
break;
}
}
pina = pouta;
pinb = poutb;
pinc = poutc;
pind = poutd;
color = !color;
}
if (nbCenterLayers!=5 && nbCenterLayers !=7){
throw NotFoundException.getNotFoundInstance();
if (nbCenterLayers != 5 && nbCenterLayers != 7) {
throw NotFoundException.getNotFoundInstance();
}
compact = nbCenterLayers==5;
@ -311,8 +306,9 @@ public final class Detector {
int targetbx = round(pinb.x+ratio*dx);
int targetby = round(pinb.y+ratio*dy);
if (!isValid(targetax, targetay) || !isValid(targetbx, targetby) || !isValid(targetcx, targetcy) || !isValid(targetdx, targetdy)){
throw NotFoundException.getNotFoundInstance();
if (!isValid(targetax, targetay) || !isValid(targetbx, targetby)
|| !isValid(targetcx, targetcy) || !isValid(targetdx, targetdy)) {
throw NotFoundException.getNotFoundInstance();
}
Point pa = new Point(targetax,targetay);
@ -321,41 +317,41 @@ public final class Detector {
Point pd = new Point(targetdx,targetdy);
return new Point[]{pa, pb, pc, pd};
}
}
/**
*
* Finds a candidate center point of an Aztec code from an image
*
* @return the center point
*/
private Point getMatrixCenter() {
/**
*
* Finds a candidate center point of an Aztec code from an image
*
* @return the center point
*/
private Point getMatrixCenter() {
ResultPoint pointA;
ResultPoint pointB;
ResultPoint pointC;
ResultPoint pointD;
//Get a white rectangle that can be the border of the matrix in center bull's eye or
try{
ResultPoint[] cornerPoints = new WhiteRectangleDetector(image).detect();
pointA = cornerPoints[0];
pointB = cornerPoints[1];
pointC = cornerPoints[2];
pointD = cornerPoints[3];
} catch (NotFoundException e){
ResultPoint pointA;
ResultPoint pointB;
ResultPoint pointC;
ResultPoint pointD;
//Get a white rectangle that can be the border of the matrix in center bull's eye or
try {
ResultPoint[] cornerPoints = new WhiteRectangleDetector(image).detect();
pointA = cornerPoints[0];
pointB = cornerPoints[1];
pointC = cornerPoints[2];
pointD = cornerPoints[3];
} catch (NotFoundException e) {
// This exception can be in case the initial rectangle is white
// In that case, surely in the bull's eye, we try to expand the rectangle.
int cx = image.width/2;
int cy = image.height/2;
pointA = getFirstDifferent(new Point(cx+15/2, cy-15/2), false, 1, -1).toResultPoint();
pointB = getFirstDifferent(new Point(cx+15/2, cy+15/2), false, 1, 1).toResultPoint();
pointC = getFirstDifferent(new Point(cx-15/2, cy+15/2), false, -1, 1).toResultPoint();
pointD = getFirstDifferent(new Point(cx-15/2, cy-15/2), false, -1, -1).toResultPoint();
// This exception can be in case the initial rectangle is white
// In that case, surely in the bull's eye, we try to expand the rectangle.
int cx = image.width/2;
int cy = image.height/2;
pointA = getFirstDifferent(new Point(cx+15/2, cy-15/2), false, 1, -1).toResultPoint();
pointB = getFirstDifferent(new Point(cx+15/2, cy+15/2), false, 1, 1).toResultPoint();
pointC = getFirstDifferent(new Point(cx-15/2, cy+15/2), false, -1, 1).toResultPoint();
pointD = getFirstDifferent(new Point(cx-15/2, cy-15/2), false, -1, -1).toResultPoint();
}
//Compute the center of the rectangle
@ -365,288 +361,255 @@ public final class Detector {
// Redetermine the white rectangle starting from previously computed center.
// This will ensure that we end up with a white rectangle in center bull's eye
// in order to compute a more accurate center.
try{
ResultPoint[] cornerPoints = new WhiteRectangleDetector(image, 15, cx, cy).detect();
try {
ResultPoint[] cornerPoints = new WhiteRectangleDetector(image, 15, cx, cy).detect();
pointA = cornerPoints[0];
pointB = cornerPoints[1];
pointC = cornerPoints[2];
pointD = cornerPoints[3];
} catch (NotFoundException e){
// This exception can be in case the initial rectangle is white
// In that case we try to expand the rectangle.
pointA = getFirstDifferent(new Point(cx+15/2, cy-15/2), false, 1, -1).toResultPoint();
pointB = getFirstDifferent(new Point(cx+15/2, cy+15/2), false, 1, 1).toResultPoint();
pointC = getFirstDifferent(new Point(cx-15/2, cy+15/2), false, -1, 1).toResultPoint();
pointD = getFirstDifferent(new Point(cx-15/2, cy-15/2), false, -1, -1).toResultPoint();
} catch (NotFoundException e) {
// This exception can be in case the initial rectangle is white
// In that case we try to expand the rectangle.
pointA = getFirstDifferent(new Point(cx+15/2, cy-15/2), false, 1, -1).toResultPoint();
pointB = getFirstDifferent(new Point(cx+15/2, cy+15/2), false, 1, 1).toResultPoint();
pointC = getFirstDifferent(new Point(cx-15/2, cy+15/2), false, -1, 1).toResultPoint();
pointD = getFirstDifferent(new Point(cx-15/2, cy-15/2), false, -1, -1).toResultPoint();
}
// Recompute the center of the rectangle
cx = round((pointA.getX() + pointD.getX() + pointB.getX() + pointC.getX())/4);
cy = round((pointA.getY() + pointD.getY() + pointB.getY() + pointC.getY())/4);
Point pCenter = new Point(cx, cy);
return pCenter;
}
return new Point(cx, cy);
}
/**
*
* Samples an Aztec matrix from an image
*
* @param image
* @param topLeft
* @param bottomLeft
* @param bottomRight
* @param topRight
* @return
* @throws NotFoundException
*/
private BitMatrix sampleGrid(BitMatrix image,
/**
* Samples an Aztec matrix from an image
*/
private BitMatrix sampleGrid(BitMatrix image,
ResultPoint topLeft,
ResultPoint bottomLeft,
ResultPoint bottomRight,
ResultPoint topRight) throws NotFoundException {
int dimension;
if (compact){
dimension = 4*nbLayers+11;
} else {
if (nbLayers <= 4){
dimension = 4*nbLayers + 15;
} else {
dimension = 4*nbLayers + 2*((nbLayers-4)/8 + 1) + 15 ;
}
}
GridSampler sampler = GridSampler.getInstance();
int dimension;
if (compact) {
dimension = 4*nbLayers+11;
} else {
if (nbLayers <= 4) {
dimension = 4*nbLayers + 15;
} else {
dimension = 4*nbLayers + 2*((nbLayers-4)/8 + 1) + 15 ;
}
}
return sampler.sampleGrid(image,
dimension,
dimension,
0.5f,
0.5f,
dimension - 0.5f,
0.5f,
dimension - 0.5f,
dimension - 0.5f,
0.5f,
dimension - 0.5f,
topLeft.getX(),
topLeft.getY(),
topRight.getX(),
topRight.getY(),
bottomRight.getX(),
bottomRight.getY(),
bottomLeft.getX(),
bottomLeft.getY());
}
GridSampler sampler = GridSampler.getInstance();
return sampler.sampleGrid(image,
dimension,
dimension,
0.5f,
0.5f,
dimension - 0.5f,
0.5f,
dimension - 0.5f,
dimension - 0.5f,
0.5f,
dimension - 0.5f,
topLeft.getX(),
topLeft.getY(),
topRight.getX(),
topRight.getY(),
bottomRight.getX(),
bottomRight.getY(),
bottomLeft.getX(),
bottomLeft.getY());
}
/**
*
* Sets number of layers and number of datablocks from parameter bits
*
* @param parameterData
*/
private void getParameters(boolean[] parameterData) {
int nbBitsForNbLayers = 0;
int nbBitsForNbDatablocks = 0;
if (compact){
nbBitsForNbLayers = 2;
nbBitsForNbDatablocks = 6;
} else {
nbBitsForNbLayers = 5;
nbBitsForNbDatablocks = 11;
}
for (int i = 0; i < nbBitsForNbLayers; i++){
nbLayers = nbLayers << 1;
if (parameterData[i]){
nbLayers += 1;
}
}
for (int i = nbBitsForNbLayers; i < nbBitsForNbLayers + nbBitsForNbDatablocks; i++){
nbDataBlocks = nbDataBlocks << 1;
if (parameterData[i]){
nbDataBlocks += 1;
}
}
int nbBitsForNbLayers;
int nbBitsForNbDatablocks;
nbLayers ++;
nbDataBlocks ++;
if (compact) {
nbBitsForNbLayers = 2;
nbBitsForNbDatablocks = 6;
} else {
nbBitsForNbLayers = 5;
nbBitsForNbDatablocks = 11;
}
for (int i = 0; i < nbBitsForNbLayers; i++) {
nbLayers <<= 1;
if (parameterData[i]) {
nbLayers += 1;
}
}
for (int i = nbBitsForNbLayers; i < nbBitsForNbLayers + nbBitsForNbDatablocks; i++) {
nbDataBlocks <<= 1;
if (parameterData[i]) {
nbDataBlocks += 1;
}
}
nbLayers ++;
nbDataBlocks ++;
}
/**
*
* Samples a line
*
* @param p1 first point
* @param p2 second point
* @param size number of bits
* @return the array of bits
*/
private boolean[] sampleLine(Point p1, Point p2,int size) {
boolean[] res = new boolean[size];
float d = distance(p1,p2);
float moduleSize = d/(size-1);
float dx = moduleSize*(p2.x - p1.x)/(float)d;
float dy = moduleSize*(p2.y - p1.y)/(float)d;
float px = p1.x;
float py = p1.y;
for (int i = 0; i < size; i++){
res[i] = image.get(round(px), round(py));
px+=dx;
py+=dy;
}
return res;
}
/**
*
* <p> returns true if the border of the rectangle passed in parameter is compound of white points only or black points only</p>
*
* @param p1
* @param p2
* @param p3
* @param p4
* @return
*/
private boolean isWhiteOrBlackRectangle(Point p1, Point p2, Point p3, Point p4) {
int corr = 3;
p1 = new Point(p1.x-corr, p1.y+corr);
p2 = new Point(p2.x-corr, p2.y-corr);
p3 = new Point(p3.x+corr, p3.y-corr);
p4 = new Point(p4.x+corr, p4.y+corr);
int cInit = getColor(p4, p1);
if (cInit == 0){
return false;
}
int c = getColor(p1, p2);
if (c!=cInit || c == 0){
return false;
}
c = getColor(p2, p3);
if (c!=cInit || c == 0){
return false;
}
c = getColor(p3, p4);
if (c!=cInit || c == 0){
return false;
}
return true;
}
/**
*
* Samples a line
*
* @param p1 first point
* @param p2 second point
* @param size number of bits
* @return the array of bits
*/
private boolean[] sampleLine(Point p1, Point p2,int size) {
/**
*
* Gets the color of a segment
*
* @param p1
* @param p2
* @return 1 if segment more than 90% black, -1 if segment is more than 90% white, 0 else
*/
private int getColor(Point p1, Point p2) {
float d = distance(p1,p2);
float dx = (p2.x - p1.x)/d;
float dy = (p2.y - p1.y)/d;
int error = 0;
float px = p1.x;
float py = p1.y;
boolean colorModel = image.get(p1.x, p1.y);
for (int i = 0; i < d; i++){
px+=dx;
py+=dy;
if (image.get(round(px), round(py)) != colorModel){
error++;
}
}
float errRatio = (float)error/d;
if (errRatio > 0.1 && errRatio < 0.9){
return 0;
}
if (errRatio <= 0.1){
return colorModel?1:-1;
} else {
return colorModel?-1:1;
}
}
boolean[] res = new boolean[size];
float d = distance(p1,p2);
float moduleSize = d/(size-1);
float dx = moduleSize*(p2.x - p1.x)/d;
float dy = moduleSize*(p2.y - p1.y)/d;
/**
*
* Gets the coordinate of the first point with a different color in the given direction
*
* @param init Initial point
* @param color Color wanted
* @param dx
* @param dy
* @return
*/
private Point getFirstDifferent(Point init, boolean color, int dx, int dy){
int x = init.x+dx;
int y = init.y+dy;
while(isValid(x,y) && image.get(x,y) == color){
x+=dx;
y+=dy;
}
x-=dx;
y-=dy;
while(isValid(x,y) && image.get(x, y) == color){
x+=dx;
}
x-=dx;
while(isValid(x,y) && image.get(x, y) == color){
y+=dy;
}
y-=dy;
return new Point(x,y);
float px = p1.x;
float py = p1.y;
for (int i = 0; i < size; i++) {
res[i] = image.get(round(px), round(py));
px+=dx;
py+=dy;
}
return res;
}
/**
* @return true if the border of the rectangle passed in parameter is compound of white points only
* or black points only
*/
private boolean isWhiteOrBlackRectangle(Point p1, Point p2, Point p3, Point p4) {
int corr = 3;
p1 = new Point(p1.x-corr, p1.y+corr);
p2 = new Point(p2.x-corr, p2.y-corr);
p3 = new Point(p3.x+corr, p3.y-corr);
p4 = new Point(p4.x+corr, p4.y+corr);
int cInit = getColor(p4, p1);
if (cInit == 0) {
return false;
}
int c = getColor(p1, p2);
if (c!=cInit || c == 0) {
return false;
}
c = getColor(p2, p3);
if (c!=cInit || c == 0) {
return false;
}
c = getColor(p3, p4);
return c == cInit && c != 0;
}
/**
* Gets the color of a segment
*
* @return 1 if segment more than 90% black, -1 if segment is more than 90% white, 0 else
*/
private int getColor(Point p1, Point p2) {
float d = distance(p1,p2);
float dx = (p2.x - p1.x)/d;
float dy = (p2.y - p1.y)/d;
int error = 0;
float px = p1.x;
float py = p1.y;
boolean colorModel = image.get(p1.x, p1.y);
for (int i = 0; i < d; i++) {
px+=dx;
py+=dy;
if (image.get(round(px), round(py)) != colorModel) {
error++;
}
}
float errRatio = (float)error/d;
if (errRatio > 0.1 && errRatio < 0.9) {
return 0;
}
if (errRatio <= 0.1) {
return colorModel?1:-1;
} else {
return colorModel?-1:1;
}
}
/**
* Gets the coordinate of the first point with a different color in the given direction
*/
private Point getFirstDifferent(Point init, boolean color, int dx, int dy) {
int x = init.x+dx;
int y = init.y+dy;
while(isValid(x,y) && image.get(x,y) == color) {
x+=dx;
y+=dy;
}
x-=dx;
y-=dy;
while(isValid(x,y) && image.get(x, y) == color) {
x+=dx;
}
x-=dx;
while(isValid(x,y) && image.get(x, y) == color) {
y+=dy;
}
y-=dy;
return new Point(x,y);
}
private class Point {
public int x;
public int y;
public ResultPoint toResultPoint(){
return new ResultPoint(x, y);
}
public Point(int x, int y){
this.x = x;
this.y = y;
}
private static class Point {
public final int x;
public final int y;
public ResultPoint toResultPoint() {
return new ResultPoint(x, y);
}
private Point(int x, int y) {
this.x = x;
this.y = y;
}
}
private boolean isValid(int x, int y) {
return (x >= 0 && x < image.width && y > 0 && y < image.height);
return (x >= 0 && x < image.width && y > 0 && y < image.height);
}
/**
@ -657,7 +620,7 @@ private Point getFirstDifferent(Point init, boolean color, int dx, int dy){
return (int) (d + 0.5f);
}
// L2 distance
// L2 distance
private static float distance(Point a, Point b) {
return (float) Math.sqrt((a.x - b.x)
* (a.x - b.x) + (a.y - b.y)

View file

@ -32,25 +32,25 @@ import com.google.zxing.common.BitMatrix;
*/
public final class WhiteRectangleDetector {
private final int INIT_SIZE = 30;
private final int CORR = 1;
private static final int INIT_SIZE = 30;
private static final int CORR = 1;
private final BitMatrix image;
private final int height;
private final int width;
private final int left_init;
private final int right_init;
private final int down_init;
private final int up_init;
private final int leftInit;
private final int rightInit;
private final int downInit;
private final int upInit;
public WhiteRectangleDetector(BitMatrix image) {
this.image = image;
height = image.getHeight();
width = image.getWidth();
left_init = (width - INIT_SIZE) >> 1;
right_init = (width + INIT_SIZE) >> 1;
up_init = (height - INIT_SIZE) >> 1;
down_init = (height + INIT_SIZE) >> 1;
leftInit = (width - INIT_SIZE) >> 1;
rightInit = (width + INIT_SIZE) >> 1;
upInit = (height - INIT_SIZE) >> 1;
downInit = (height + INIT_SIZE) >> 1;
}
public WhiteRectangleDetector(BitMatrix image, int INIT_SIZE, int x, int y) {
@ -58,10 +58,10 @@ public final class WhiteRectangleDetector {
height = image.getHeight();
width = image.getWidth();
int halfsize = INIT_SIZE >> 1;
left_init = x - halfsize;
right_init = x + halfsize;
up_init = y - halfsize;
down_init = y + halfsize;
leftInit = x - halfsize;
rightInit = x + halfsize;
upInit = y - halfsize;
downInit = y + halfsize;
}
/**
@ -80,10 +80,10 @@ public final class WhiteRectangleDetector {
*/
public ResultPoint[] detect() throws NotFoundException {
int left = left_init;
int right = right_init;
int up = up_init;
int down = down_init;
int left = leftInit;
int right = rightInit;
int up = upInit;
int down = downInit;
boolean sizeExceeded = false;
boolean aBlackPointFoundOnBorder = true;
boolean atLeastOneBlackPointFoundOnBorder = false;

View file

@ -85,7 +85,9 @@ public final class GenericGF {
}
private void checkInit(){
if (!initialized) initialize();
if (!initialized) {
initialize();
}
}
GenericGFPoly getZero() {

View file

@ -122,8 +122,9 @@ public final class CommandLineRunner {
vector.addElement(BarcodeFormat.ITF);
vector.addElement(BarcodeFormat.QR_CODE);
vector.addElement(BarcodeFormat.DATA_MATRIX);
vector.addElement(BarcodeFormat.AZTEC);
vector.addElement(BarcodeFormat.PDF417);
//vector.addElement(BarcodeFormat.CODABAR);
vector.addElement(BarcodeFormat.CODABAR);
}
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
if (tryHarder) {

View file

@ -109,11 +109,12 @@ public final class DecodeServlet extends HttpServlet {
possibleFormats.add(BarcodeFormat.CODE_39);
possibleFormats.add(BarcodeFormat.CODE_93);
possibleFormats.add(BarcodeFormat.CODE_128);
//possibleFormats.add(BarcodeFormat.CODABAR);
possibleFormats.add(BarcodeFormat.CODABAR);
possibleFormats.add(BarcodeFormat.ITF);
possibleFormats.add(BarcodeFormat.RSS14);
possibleFormats.add(BarcodeFormat.QR_CODE);
possibleFormats.add(BarcodeFormat.DATA_MATRIX);
possibleFormats.add(BarcodeFormat.AZTEC);
possibleFormats.add(BarcodeFormat.PDF417);
HINTS.put(DecodeHintType.POSSIBLE_FORMATS, possibleFormats);
HINTS_PURE = new Hashtable<DecodeHintType, Object>(HINTS);