mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Minor style changes, streamline Aztec detector and CommandLineRunner slightly
git-svn-id: https://zxing.googlecode.com/svn/trunk@2521 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
f41a07ebcd
commit
6f18b47af4
|
@ -28,8 +28,8 @@ import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Encapsulates logic that can detect an Aztec Code in an image, even if the Aztec Code
|
* Encapsulates logic that can detect an Aztec Code in an image, even if the Aztec Code
|
||||||
* is rotated or skewed, or partially obscured.</p>
|
* is rotated or skewed, or partially obscured.
|
||||||
*
|
*
|
||||||
* @author David Olivier
|
* @author David Olivier
|
||||||
*/
|
*/
|
||||||
|
@ -48,7 +48,7 @@ public final class Detector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Detects an Aztec Code in an image.</p>
|
* Detects an Aztec Code in an image.
|
||||||
*
|
*
|
||||||
* @return {@link AztecDetectorResult} encapsulating results of detecting an Aztec Code
|
* @return {@link AztecDetectorResult} encapsulating results of detecting an Aztec Code
|
||||||
* @throws NotFoundException if no Aztec Code can be found
|
* @throws NotFoundException if no Aztec Code can be found
|
||||||
|
@ -74,28 +74,29 @@ public final class Detector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p> Extracts the number of data layers and data blocks from the layer around the bull's eye </p>
|
* Extracts the number of data layers and data blocks from the layer around the bull's eye.
|
||||||
*
|
*
|
||||||
* @param bullEyeCornerPoints the array of bull's eye corners
|
* @param bullEyeCornerPoints the array of bull's eye corners
|
||||||
* @throws NotFoundException in case of too many errors or invalid parameters
|
* @throws NotFoundException in case of too many errors or invalid parameters
|
||||||
*/
|
*/
|
||||||
private void extractParameters(Point[] bullEyeCornerPoints)
|
private void extractParameters(Point[] bullEyeCornerPoints) throws NotFoundException {
|
||||||
throws NotFoundException {
|
|
||||||
|
int twoCenterLayers = 2 * nbCenterLayers;
|
||||||
|
|
||||||
// Get the bits around the bull's eye
|
// Get the bits around the bull's eye
|
||||||
boolean[] resab = sampleLine(bullEyeCornerPoints[0], bullEyeCornerPoints[1], 2*nbCenterLayers+1);
|
boolean[] resab = sampleLine(bullEyeCornerPoints[0], bullEyeCornerPoints[1], twoCenterLayers+1);
|
||||||
boolean[] resbc = sampleLine(bullEyeCornerPoints[1], bullEyeCornerPoints[2], 2*nbCenterLayers+1);
|
boolean[] resbc = sampleLine(bullEyeCornerPoints[1], bullEyeCornerPoints[2], twoCenterLayers+1);
|
||||||
boolean[] rescd = sampleLine(bullEyeCornerPoints[2], bullEyeCornerPoints[3], 2*nbCenterLayers+1);
|
boolean[] rescd = sampleLine(bullEyeCornerPoints[2], bullEyeCornerPoints[3], twoCenterLayers+1);
|
||||||
boolean[] resda = sampleLine(bullEyeCornerPoints[3], bullEyeCornerPoints[0], 2*nbCenterLayers+1);
|
boolean[] resda = sampleLine(bullEyeCornerPoints[3], bullEyeCornerPoints[0], twoCenterLayers+1);
|
||||||
|
|
||||||
// Determine the orientation of the matrix
|
// Determine the orientation of the matrix
|
||||||
if (resab[0] && resab[2 * nbCenterLayers]) {
|
if (resab[0] && resab[twoCenterLayers]) {
|
||||||
shift = 0;
|
shift = 0;
|
||||||
} else if (resbc[0] && resbc[2 * nbCenterLayers]) {
|
} else if (resbc[0] && resbc[twoCenterLayers]) {
|
||||||
shift = 1;
|
shift = 1;
|
||||||
} else if (rescd[0] && rescd[2 * nbCenterLayers]) {
|
} else if (rescd[0] && rescd[twoCenterLayers]) {
|
||||||
shift = 2;
|
shift = 2;
|
||||||
} else if (resda[0] && resda[2 * nbCenterLayers]) {
|
} else if (resda[0] && resda[twoCenterLayers]) {
|
||||||
shift = 3;
|
shift = 3;
|
||||||
} else {
|
} else {
|
||||||
throw NotFoundException.getNotFoundInstance();
|
throw NotFoundException.getNotFoundInstance();
|
||||||
|
@ -118,9 +119,9 @@ public final class Detector {
|
||||||
}
|
}
|
||||||
|
|
||||||
parameterData = new boolean[28];
|
parameterData = new boolean[28];
|
||||||
for (int i = 0; i < 28; i++) {
|
for (int i = 0; i < 28; i++) {
|
||||||
parameterData[i] = shiftedParameterData[(i+shift*7)%28];
|
parameterData[i] = shiftedParameterData[(i+shift*7)%28];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
shiftedParameterData = new boolean[40];
|
shiftedParameterData = new boolean[40];
|
||||||
for (int i = 0; i < 11; i++) {
|
for (int i = 0; i < 11; i++) {
|
||||||
|
@ -132,16 +133,16 @@ public final class Detector {
|
||||||
}
|
}
|
||||||
if (i > 5) {
|
if (i > 5) {
|
||||||
shiftedParameterData[i-1] = resab[2+i];
|
shiftedParameterData[i-1] = resab[2+i];
|
||||||
shiftedParameterData[i+10-1] = resbc[2+i];
|
shiftedParameterData[i+9] = resbc[2+i];
|
||||||
shiftedParameterData[i+20-1] = rescd[2+i];
|
shiftedParameterData[i+19] = rescd[2+i];
|
||||||
shiftedParameterData[i+30-1] = resda[2+i];
|
shiftedParameterData[i+29] = resda[2+i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parameterData = new boolean[40];
|
parameterData = new boolean[40];
|
||||||
for (int i = 0; i < 40; i++) {
|
for (int i = 0; i < 40; i++) {
|
||||||
parameterData[i] = shiftedParameterData[(i+shift*10)%40];
|
parameterData[i] = shiftedParameterData[(i+shift*10)%40];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// corrects the error using RS algorithm
|
// corrects the error using RS algorithm
|
||||||
|
@ -152,8 +153,7 @@ public final class Detector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Gets the Aztec code corners from the bull's eye corners and the parameters.
|
||||||
* <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
|
* @param bullEyeCornerPoints the array of bull's eye corners
|
||||||
* @return the array of aztec code corners
|
* @return the array of aztec code corners
|
||||||
|
@ -185,18 +185,25 @@ public final class Detector {
|
||||||
int targetbx = MathUtils.round(bullEyeCornerPoints[1].x + ratio * dx);
|
int targetbx = MathUtils.round(bullEyeCornerPoints[1].x + ratio * dx);
|
||||||
int targetby = MathUtils.round(bullEyeCornerPoints[1].y+ratio*dy);
|
int targetby = MathUtils.round(bullEyeCornerPoints[1].y+ratio*dy);
|
||||||
|
|
||||||
if (!isValid(targetax, targetay) || !isValid(targetbx, targetby) || !isValid(targetcx, targetcy) || !isValid(targetdx, targetdy)) {
|
if (!isValid(targetax, targetay) ||
|
||||||
|
!isValid(targetbx, targetby) ||
|
||||||
|
!isValid(targetcx, targetcy) ||
|
||||||
|
!isValid(targetdx, targetdy)) {
|
||||||
throw NotFoundException.getNotFoundInstance();
|
throw NotFoundException.getNotFoundInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ResultPoint[]{new ResultPoint(targetax, targetay), new ResultPoint(targetbx, targetby), new ResultPoint(targetcx, targetcy), new ResultPoint(targetdx, targetdy)};
|
return new ResultPoint[]{
|
||||||
|
new ResultPoint(targetax, targetay),
|
||||||
|
new ResultPoint(targetbx, targetby),
|
||||||
|
new ResultPoint(targetcx, targetcy),
|
||||||
|
new ResultPoint(targetdx, targetdy)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Corrects the parameter bits using Reed-Solomon algorithm.
|
||||||
*
|
*
|
||||||
* <p> Corrects the parameter bits using Reed-Solomon algorithm </p>
|
* @param parameterData parameter bits
|
||||||
*
|
|
||||||
* @param parameterData paremeter bits
|
|
||||||
* @param compact true if this is a compact Aztec code
|
* @param compact true if this is a compact Aztec code
|
||||||
* @throws NotFoundException if the array contains too many errors
|
* @throws NotFoundException if the array contains too many errors
|
||||||
*/
|
*/
|
||||||
|
@ -235,17 +242,16 @@ public final class Detector {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < numDataCodewords; i ++) {
|
for (int i = 0; i < numDataCodewords; i ++) {
|
||||||
int flag = 1;
|
int flag = 1;
|
||||||
for (int j = 1; j <= codewordSize; j++) {
|
for (int j = 1; j <= codewordSize; j++) {
|
||||||
parameterData[i*codewordSize+codewordSize-j] = (parameterWords[i] & flag) == flag;
|
parameterData[i*codewordSize+codewordSize-j] = (parameterWords[i] & flag) == flag;
|
||||||
flag <<= 1;
|
flag <<= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Finds the corners of a bull-eye centered on the passed point.
|
||||||
* <p> Finds the corners of a bull-eye centered on the passed point </p>
|
|
||||||
*
|
*
|
||||||
* @param pCenter Center point
|
* @param pCenter Center point
|
||||||
* @return The corners of the bull-eye
|
* @return The corners of the bull-eye
|
||||||
|
@ -308,21 +314,22 @@ public final class Detector {
|
||||||
int targetbx = MathUtils.round(pinb.x+ratio*dx);
|
int targetbx = MathUtils.round(pinb.x+ratio*dx);
|
||||||
int targetby = MathUtils.round(pinb.y+ratio*dy);
|
int targetby = MathUtils.round(pinb.y+ratio*dy);
|
||||||
|
|
||||||
if (!isValid(targetax, targetay) || !isValid(targetbx, targetby)
|
if (!isValid(targetax, targetay) ||
|
||||||
|| !isValid(targetcx, targetcy) || !isValid(targetdx, targetdy)) {
|
!isValid(targetbx, targetby) ||
|
||||||
|
!isValid(targetcx, targetcy) ||
|
||||||
|
!isValid(targetdx, targetdy)) {
|
||||||
throw NotFoundException.getNotFoundInstance();
|
throw NotFoundException.getNotFoundInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
Point pa = new Point(targetax,targetay);
|
return new Point[] {
|
||||||
Point pb = new Point(targetbx,targetby);
|
new Point(targetax,targetay),
|
||||||
Point pc = new Point(targetcx,targetcy);
|
new Point(targetbx,targetby),
|
||||||
Point pd = new Point(targetdx,targetdy);
|
new Point(targetcx,targetcy),
|
||||||
|
new Point(targetdx,targetdy)
|
||||||
return new Point[]{pa, pb, pc, pd};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Finds a candidate center point of an Aztec code from an image
|
* Finds a candidate center point of an Aztec code from an image
|
||||||
*
|
*
|
||||||
* @return the center point
|
* @return the center point
|
||||||
|
@ -349,16 +356,16 @@ public final class Detector {
|
||||||
// In that case, surely in the bull's eye, we try to expand the rectangle.
|
// In that case, surely in the bull's eye, we try to expand the rectangle.
|
||||||
int cx = image.getWidth()/2;
|
int cx = image.getWidth()/2;
|
||||||
int cy = image.getHeight()/2;
|
int cy = image.getHeight()/2;
|
||||||
pointA = getFirstDifferent(new Point(cx+15/2, cy-15/2), false, 1, -1).toResultPoint();
|
pointA = getFirstDifferent(new Point(cx+7, cy-7), false, 1, -1).toResultPoint();
|
||||||
pointB = getFirstDifferent(new Point(cx+15/2, cy+15/2), false, 1, 1).toResultPoint();
|
pointB = getFirstDifferent(new Point(cx+7, cy+7), false, 1, 1).toResultPoint();
|
||||||
pointC = getFirstDifferent(new Point(cx-15/2, cy+15/2), false, -1, 1).toResultPoint();
|
pointC = getFirstDifferent(new Point(cx-7, cy+7), false, -1, 1).toResultPoint();
|
||||||
pointD = getFirstDifferent(new Point(cx-15/2, cy-15/2), false, -1, -1).toResultPoint();
|
pointD = getFirstDifferent(new Point(cx-7, cy-7), false, -1, -1).toResultPoint();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Compute the center of the rectangle
|
//Compute the center of the rectangle
|
||||||
int cx = MathUtils.round((pointA.getX() + pointD.getX() + pointB.getX() + pointC.getX())/4);
|
int cx = MathUtils.round((pointA.getX() + pointD.getX() + pointB.getX() + pointC.getX()) / 4.0f);
|
||||||
int cy = MathUtils.round((pointA.getY() + pointD.getY() + pointB.getY() + pointC.getY())/4);
|
int cy = MathUtils.round((pointA.getY() + pointD.getY() + pointB.getY() + pointC.getY()) / 4.0f);
|
||||||
|
|
||||||
// Redetermine the white rectangle starting from previously computed center.
|
// 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
|
// This will ensure that we end up with a white rectangle in center bull's eye
|
||||||
|
@ -373,16 +380,16 @@ public final class Detector {
|
||||||
|
|
||||||
// This exception can be in case the initial rectangle is white
|
// This exception can be in case the initial rectangle is white
|
||||||
// In that case we try to expand the rectangle.
|
// In that case we try to expand the rectangle.
|
||||||
pointA = getFirstDifferent(new Point(cx+15/2, cy-15/2), false, 1, -1).toResultPoint();
|
pointA = getFirstDifferent(new Point(cx+7, cy-7), false, 1, -1).toResultPoint();
|
||||||
pointB = getFirstDifferent(new Point(cx+15/2, cy+15/2), false, 1, 1).toResultPoint();
|
pointB = getFirstDifferent(new Point(cx+7, cy+7), false, 1, 1).toResultPoint();
|
||||||
pointC = getFirstDifferent(new Point(cx-15/2, cy+15/2), false, -1, 1).toResultPoint();
|
pointC = getFirstDifferent(new Point(cx-7, cy+7), false, -1, 1).toResultPoint();
|
||||||
pointD = getFirstDifferent(new Point(cx-15/2, cy-15/2), false, -1, -1).toResultPoint();
|
pointD = getFirstDifferent(new Point(cx-7, cy-7), false, -1, -1).toResultPoint();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recompute the center of the rectangle
|
// Recompute the center of the rectangle
|
||||||
cx = MathUtils.round((pointA.getX() + pointD.getX() + pointB.getX() + pointC.getX())/4);
|
cx = MathUtils.round((pointA.getX() + pointD.getX() + pointB.getX() + pointC.getX()) / 4.0f);
|
||||||
cy = MathUtils.round((pointA.getY() + pointD.getY() + pointB.getY() + pointC.getY())/4);
|
cy = MathUtils.round((pointA.getY() + pointD.getY() + pointB.getY() + pointC.getY()) / 4.0f);
|
||||||
|
|
||||||
return new Point(cx, cy);
|
return new Point(cx, cy);
|
||||||
}
|
}
|
||||||
|
@ -431,7 +438,7 @@ public final class Detector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets number of layers and number of datablocks from parameter bits
|
* Sets number of layers and number of data blocks from parameter bits
|
||||||
*/
|
*/
|
||||||
private void getParameters(boolean[] parameterData) {
|
private void getParameters(boolean[] parameterData) {
|
||||||
|
|
||||||
|
@ -449,24 +456,22 @@ public final class Detector {
|
||||||
for (int i = 0; i < nbBitsForNbLayers; i++) {
|
for (int i = 0; i < nbBitsForNbLayers; i++) {
|
||||||
nbLayers <<= 1;
|
nbLayers <<= 1;
|
||||||
if (parameterData[i]) {
|
if (parameterData[i]) {
|
||||||
nbLayers += 1;
|
nbLayers++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = nbBitsForNbLayers; i < nbBitsForNbLayers + nbBitsForNbDatablocks; i++) {
|
for (int i = nbBitsForNbLayers; i < nbBitsForNbLayers + nbBitsForNbDatablocks; i++) {
|
||||||
nbDataBlocks <<= 1;
|
nbDataBlocks <<= 1;
|
||||||
if (parameterData[i]) {
|
if (parameterData[i]) {
|
||||||
nbDataBlocks += 1;
|
nbDataBlocks++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nbLayers ++;
|
nbLayers++;
|
||||||
nbDataBlocks ++;
|
nbDataBlocks++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Samples a line
|
* Samples a line
|
||||||
*
|
*
|
||||||
* @param p1 first point
|
* @param p1 first point
|
||||||
|
@ -487,8 +492,8 @@ public final class Detector {
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
res[i] = image.get(MathUtils.round(px), MathUtils.round(py));
|
res[i] = image.get(MathUtils.round(px), MathUtils.round(py));
|
||||||
px+=dx;
|
px += dx;
|
||||||
py+=dy;
|
py += dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -560,15 +565,11 @@ public final class Detector {
|
||||||
|
|
||||||
float errRatio = (float)error/d;
|
float errRatio = (float)error/d;
|
||||||
|
|
||||||
if (errRatio > 0.1 && errRatio < 0.9) {
|
if (errRatio > 0.1f && errRatio < 0.9f) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errRatio <= 0.1) {
|
return (errRatio <= 0.1f) == colorModel ? 1 : -1;
|
||||||
return colorModel?1:-1;
|
|
||||||
} else {
|
|
||||||
return colorModel?-1:1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -598,20 +599,6 @@ public final class Detector {
|
||||||
|
|
||||||
return new Point(x,y);
|
return new Point(x,y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final 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) {
|
private boolean isValid(int x, int y) {
|
||||||
return x >= 0 && x < image.getWidth() && y > 0 && y < image.getHeight();
|
return x >= 0 && x < image.getWidth() && y > 0 && y < image.getHeight();
|
||||||
|
@ -621,4 +608,18 @@ public final class Detector {
|
||||||
return MathUtils.distance(a.x, a.y, b.x, b.y);
|
return MathUtils.distance(a.x, a.y, b.x, b.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final class Point {
|
||||||
|
final int x;
|
||||||
|
final int y;
|
||||||
|
|
||||||
|
ResultPoint toResultPoint() {
|
||||||
|
return new ResultPoint(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point(int x, int y) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,10 @@
|
||||||
|
|
||||||
package com.google.zxing.client.result;
|
package com.google.zxing.client.result;
|
||||||
|
|
||||||
import com.google.zxing.Result;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Abstract class representing the result of decoding a barcode, as more than
|
* <p>Abstract class representing the result of decoding a barcode, as more than
|
||||||
* a String -- as some type of structured data. This might be a subclass which represents
|
* a String -- as some type of structured data. This might be a subclass which represents
|
||||||
* a URL, or an e-mail address. {@link ResultParser#parseResult(Result)} will turn a raw
|
* a URL, or an e-mail address. {@link ResultParser#parseResult(com.google.zxing.Result)} will turn a raw
|
||||||
* decoded string into the most appropriate type of structured representation.</p>
|
* decoded string into the most appropriate type of structured representation.</p>
|
||||||
*
|
*
|
||||||
* <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
|
* <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
|
||||||
|
|
|
@ -287,7 +287,7 @@ public final class WhiteRectangleDetector {
|
||||||
float ti = t.getX();
|
float ti = t.getX();
|
||||||
float tj = t.getY();
|
float tj = t.getY();
|
||||||
|
|
||||||
if (yi < width / 2) {
|
if (yi < width / 2.0f) {
|
||||||
return new ResultPoint[]{
|
return new ResultPoint[]{
|
||||||
new ResultPoint(ti - CORR, tj + CORR),
|
new ResultPoint(ti - CORR, tj + CORR),
|
||||||
new ResultPoint(zi + CORR, zj + CORR),
|
new ResultPoint(zi + CORR, zj + CORR),
|
||||||
|
|
|
@ -16,12 +16,10 @@
|
||||||
|
|
||||||
package com.google.zxing.oned;
|
package com.google.zxing.oned;
|
||||||
|
|
||||||
import com.google.zxing.common.BitMatrix;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class renders CodaBar as {@link BitMatrix}.
|
* This class renders CodaBar as {@code boolean[]}.
|
||||||
*
|
*
|
||||||
* @author dsbnatut@gmail.com (Kazuki Nishiura)
|
* @author dsbnatut@gmail.com (Kazuki Nishiura)
|
||||||
*/
|
*/
|
||||||
|
@ -30,9 +28,6 @@ public final class CodaBarWriter extends OneDimensionalCodeWriter {
|
||||||
private static final char[] START_CHARS = {'A', 'B', 'C', 'D'};
|
private static final char[] START_CHARS = {'A', 'B', 'C', 'D'};
|
||||||
private static final char[] END_CHARS = {'T', 'N', '*', 'E'};
|
private static final char[] END_CHARS = {'T', 'N', '*', 'E'};
|
||||||
|
|
||||||
/*
|
|
||||||
* @see OneDimensionalCodeWriter#encode(String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean[] encode(String contents) {
|
public boolean[] encode(String contents) {
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ public abstract class OneDimensionalCodeWriter implements Writer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode the contents to byte array expression of one-dimensional barcode.
|
* Encode the contents to boolean array expression of one-dimensional barcode.
|
||||||
* Start code and end code should be included in result, and side margins should not be included.
|
* Start code and end code should be included in result, and side margins should not be included.
|
||||||
*
|
*
|
||||||
* @return a {@code boolean[]} of horizontal pixels (false = white, true = black)
|
* @return a {@code boolean[]} of horizontal pixels (false = white, true = black)
|
||||||
|
|
|
@ -449,10 +449,8 @@ public final class RSSExpandedReader extends AbstractRSSReader {
|
||||||
|
|
||||||
DataCharacter leftChar = this.decodeDataCharacter(row, pattern, isOddPattern, true);
|
DataCharacter leftChar = this.decodeDataCharacter(row, pattern, isOddPattern, true);
|
||||||
|
|
||||||
if (!previousPairs.isEmpty()){
|
if (!previousPairs.isEmpty() && previousPairs.get(previousPairs.size()-1).mustBeLast()) {
|
||||||
if (previousPairs.get(previousPairs.size()-1).mustBeLast()){
|
throw NotFoundException.getNotFoundInstance();
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DataCharacter rightChar;
|
DataCharacter rightChar;
|
||||||
|
|
|
@ -212,10 +212,8 @@ final class BitMatrixParser {
|
||||||
} else {
|
} else {
|
||||||
// Left row indicator column
|
// Left row indicator column
|
||||||
int cw = getCodeword(symbol);
|
int cw = getCodeword(symbol);
|
||||||
if (ecLevel < 0) {
|
if (ecLevel < 0 && rowNumber % 3 == 1) {
|
||||||
if (rowNumber % 3 == 1) {
|
leftColumnECData = cw;
|
||||||
leftColumnECData = cw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
symbol = 0;
|
symbol = 0;
|
||||||
|
@ -227,12 +225,10 @@ final class BitMatrixParser {
|
||||||
//columns--;
|
//columns--;
|
||||||
// Overwrite the last codeword i.e. Right Row Indicator
|
// Overwrite the last codeword i.e. Right Row Indicator
|
||||||
--next;
|
--next;
|
||||||
if (ecLevel < 0) {
|
if (ecLevel < 0 && rowNumber % 3 == 2) {
|
||||||
if (rowNumber % 3 == 2) {
|
rightColumnECData = codewords[next];
|
||||||
rightColumnECData = codewords[next];
|
if (rightColumnECData == leftColumnECData && leftColumnECData != 0) {
|
||||||
if (rightColumnECData == leftColumnECData && leftColumnECData != 0) {
|
ecLevel = ((rightColumnECData % 30) - rows % 3) / 3;
|
||||||
ecLevel = ((rightColumnECData % 30) - rows % 3) / 3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
codewords[next] = 0;
|
codewords[next] = 0;
|
||||||
|
@ -243,7 +239,6 @@ final class BitMatrixParser {
|
||||||
/**
|
/**
|
||||||
* Translate the symbol into a codeword.
|
* Translate the symbol into a codeword.
|
||||||
*
|
*
|
||||||
* @param symbol
|
|
||||||
* @return the codeword corresponding to the symbol.
|
* @return the codeword corresponding to the symbol.
|
||||||
*/
|
*/
|
||||||
private static int getCodeword(long symbol) {
|
private static int getCodeword(long symbol) {
|
||||||
|
|
|
@ -535,35 +535,6 @@ final class PDF417 {
|
||||||
return barcodeMatrix;
|
return barcodeMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the necessary number of rows as described in annex Q of ISO/IEC 15438:2001(E).
|
|
||||||
*
|
|
||||||
* @param m the number of source codewords prior to the additional of the Symbol Length
|
|
||||||
* Descriptor and any pad codewords
|
|
||||||
* @param k the number of error correction codewords
|
|
||||||
* @param c the number of columns in the symbol in the data region (excluding start, stop and
|
|
||||||
* row indicator codewords)
|
|
||||||
* @return the number of rows in the symbol (r)
|
|
||||||
*/
|
|
||||||
private static int getNumberOfRows(int m, int k, int c) throws WriterException {
|
|
||||||
int r = calculateNumberOfRows(m, k, c);
|
|
||||||
if (r > 90) {
|
|
||||||
throw new WriterException(
|
|
||||||
"The message doesn't fit in the configured symbol size."
|
|
||||||
+ " The resultant number of rows for this barcode exceeds 90."
|
|
||||||
+ " Please increase the number of columns or decrease the error correction"
|
|
||||||
+ " level to reduce the number of rows.");
|
|
||||||
}
|
|
||||||
if (r < 2) {
|
|
||||||
throw new WriterException(
|
|
||||||
"The message is too short for the configured symbol size."
|
|
||||||
+ " The resultant number of rows is less than 3."
|
|
||||||
+ " Please decrease the number of columns or increase the error correction"
|
|
||||||
+ " level to increase the number of rows.");
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the necessary number of rows as described in annex Q of ISO/IEC 15438:2001(E).
|
* Calculates the necessary number of rows as described in annex Q of ISO/IEC 15438:2001(E).
|
||||||
*
|
*
|
||||||
|
|
|
@ -27,6 +27,11 @@ import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This simple command line utility decodes files, directories of files, or URIs which are passed
|
* This simple command line utility decodes files, directories of files, or URIs which are passed
|
||||||
|
@ -48,7 +53,7 @@ public final class CommandLineRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
Config config = new Config();
|
Config config = new Config();
|
||||||
Inputs inputs = new Inputs();
|
Queue<String> inputs = new ConcurrentLinkedQueue<String>();
|
||||||
|
|
||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
if ("--try_harder".equals(arg)) {
|
if ("--try_harder".equals(arg)) {
|
||||||
|
@ -74,11 +79,6 @@ public final class CommandLineRunner {
|
||||||
crop[i] = Integer.parseInt(tokens[i]);
|
crop[i] = Integer.parseInt(tokens[i]);
|
||||||
}
|
}
|
||||||
config.setCrop(crop);
|
config.setCrop(crop);
|
||||||
} else if (arg.startsWith("--threads") && arg.length() >= 10) {
|
|
||||||
int threads = Integer.parseInt(arg.substring(10));
|
|
||||||
if (threads > 1) {
|
|
||||||
config.setThreads(threads);
|
|
||||||
}
|
|
||||||
} else if (arg.startsWith("-")) {
|
} else if (arg.startsWith("-")) {
|
||||||
System.err.println("Unknown command line option " + arg);
|
System.err.println("Unknown command line option " + arg);
|
||||||
printUsage();
|
printUsage();
|
||||||
|
@ -93,19 +93,20 @@ public final class CommandLineRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DecodeThread> threads = new ArrayList<DecodeThread>(config.getThreads());
|
int numThreads = Runtime.getRuntime().availableProcessors();
|
||||||
for (int x = 0; x < config.getThreads(); x++) {
|
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
|
||||||
DecodeThread thread = new DecodeThread(config, inputs);
|
List<Future<Integer>> futures = new ArrayList<Future<Integer>>(numThreads);
|
||||||
threads.add(thread);
|
for (int x = 0; x < numThreads; x++) {
|
||||||
thread.start();
|
futures.add(executor.submit(new DecodeWorker(config, inputs)));
|
||||||
}
|
}
|
||||||
|
executor.shutdown();
|
||||||
|
|
||||||
int successful = 0;
|
int successful = 0;
|
||||||
for (int x = 0; x < config.getThreads(); x++) {
|
for (Future<Integer> future : futures) {
|
||||||
threads.get(x).join();
|
successful += future.get();
|
||||||
successful += threads.get(x).getSuccessful();
|
|
||||||
}
|
}
|
||||||
int total = inputs.getInputCount();
|
|
||||||
|
int total = inputs.size();
|
||||||
if (total > 1) {
|
if (total > 1) {
|
||||||
System.out.println("\nDecoded " + successful + " files out of " + total +
|
System.out.println("\nDecoded " + successful + " files out of " + total +
|
||||||
" successfully (" + (successful * 100 / total) + "%)\n");
|
" successfully (" + (successful * 100 / total) + "%)\n");
|
||||||
|
@ -114,7 +115,7 @@ public final class CommandLineRunner {
|
||||||
|
|
||||||
// Build all the inputs up front into a single flat list, so the threads can atomically pull
|
// Build all the inputs up front into a single flat list, so the threads can atomically pull
|
||||||
// paths/URLs off the queue.
|
// paths/URLs off the queue.
|
||||||
private static void addArgumentToInputs(String argument, Config config, Inputs inputs) throws IOException {
|
private static void addArgumentToInputs(String argument, Config config, Queue<String> inputs) throws IOException {
|
||||||
File inputFile = new File(argument);
|
File inputFile = new File(argument);
|
||||||
if (inputFile.exists()) {
|
if (inputFile.exists()) {
|
||||||
if (inputFile.isDirectory()) {
|
if (inputFile.isDirectory()) {
|
||||||
|
@ -124,7 +125,7 @@ public final class CommandLineRunner {
|
||||||
if (filename.startsWith(".")) {
|
if (filename.startsWith(".")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Recurse on nested directories if requested, otherwise skip them.
|
// Recur on nested directories if requested, otherwise skip them.
|
||||||
if (singleFile.isDirectory()) {
|
if (singleFile.isDirectory()) {
|
||||||
if (config.isRecursive()) {
|
if (config.isRecursive()) {
|
||||||
addArgumentToInputs(singleFile.getAbsolutePath(), config, inputs);
|
addArgumentToInputs(singleFile.getAbsolutePath(), config, inputs);
|
||||||
|
@ -135,13 +136,13 @@ public final class CommandLineRunner {
|
||||||
if (filename.endsWith(".txt") || filename.contains(".mono.png")) {
|
if (filename.endsWith(".txt") || filename.contains(".mono.png")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
inputs.addInput(singleFile.getCanonicalPath());
|
inputs.add(singleFile.getCanonicalPath());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
inputs.addInput(inputFile.getCanonicalPath());
|
inputs.add(inputFile.getCanonicalPath());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
inputs.addInput(argument);
|
inputs.add(argument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,6 @@ final class Config {
|
||||||
private boolean brief;
|
private boolean brief;
|
||||||
private boolean recursive;
|
private boolean recursive;
|
||||||
private int[] crop;
|
private int[] crop;
|
||||||
private int threads = 1;
|
|
||||||
|
|
||||||
Map<DecodeHintType,?> getHints() {
|
Map<DecodeHintType,?> getHints() {
|
||||||
return hints;
|
return hints;
|
||||||
|
@ -114,11 +113,4 @@ final class Config {
|
||||||
this.crop = crop;
|
this.crop = crop;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getThreads() {
|
|
||||||
return threads;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setThreads(int threads) {
|
|
||||||
this.threads = threads;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,68 +42,58 @@ import java.io.Writer;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One of a pool of threads which pulls images off the Inputs queue and decodes them in parallel.
|
* One of a pool of threads which pulls images off the Inputs queue and decodes them in parallel.
|
||||||
*
|
*
|
||||||
* @see CommandLineRunner
|
* @see CommandLineRunner
|
||||||
*/
|
*/
|
||||||
final class DecodeThread extends Thread {
|
final class DecodeWorker implements Callable<Integer> {
|
||||||
|
|
||||||
private int successful;
|
|
||||||
private final Config config;
|
private final Config config;
|
||||||
private final Inputs inputs;
|
private final Queue<String> inputs;
|
||||||
|
|
||||||
DecodeThread(Config config, Inputs inputs) {
|
DecodeWorker(Config config, Queue<String> inputs) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.inputs = inputs;
|
this.inputs = inputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public Integer call() throws IOException {
|
||||||
while (true) {
|
int successful = 0;
|
||||||
String input = inputs.getNextInput();
|
String input;
|
||||||
if (input == null) {
|
while ((input = inputs.poll()) != null) {
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
File inputFile = new File(input);
|
File inputFile = new File(input);
|
||||||
if (inputFile.exists()) {
|
if (inputFile.exists()) {
|
||||||
try {
|
if (config.isMulti()) {
|
||||||
if (config.isMulti()) {
|
Result[] results = decodeMulti(inputFile.toURI(), config.getHints());
|
||||||
Result[] results = decodeMulti(inputFile.toURI(), config.getHints());
|
if (results != null) {
|
||||||
if (results != null) {
|
successful++;
|
||||||
successful++;
|
if (config.isDumpResults()) {
|
||||||
if (config.isDumpResults()) {
|
dumpResultMulti(inputFile, results);
|
||||||
dumpResultMulti(inputFile, results);
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
Result result = decode(inputFile.toURI(), config.getHints());
|
||||||
Result result = decode(inputFile.toURI(), config.getHints());
|
if (result != null) {
|
||||||
if (result != null) {
|
successful++;
|
||||||
successful++;
|
if (config.isDumpResults()) {
|
||||||
if (config.isDumpResults()) {
|
dumpResult(inputFile, result);
|
||||||
dumpResult(inputFile, result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
if (decode(URI.create(input), config.getHints()) != null) {
|
||||||
if (decode(new URI(input), config.getHints()) != null) {
|
successful++;
|
||||||
successful++;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public int getSuccessful() {
|
|
||||||
return successful;
|
return successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void dumpResult(File input, Result result) throws IOException {
|
private static void dumpResult(File input, Result result) throws IOException {
|
||||||
String name = input.getCanonicalPath();
|
String name = input.getCanonicalPath();
|
||||||
int pos = name.lastIndexOf('.');
|
int pos = name.lastIndexOf('.');
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.client.j2se;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the collection of all images files/URLs to decode.
|
|
||||||
*/
|
|
||||||
final class Inputs {
|
|
||||||
|
|
||||||
private final List<String> inputs = new ArrayList<String>(10);
|
|
||||||
private int position = 0;
|
|
||||||
|
|
||||||
public synchronized void addInput(String pathOrUrl) {
|
|
||||||
inputs.add(pathOrUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized String getNextInput() {
|
|
||||||
if (position < inputs.size()) {
|
|
||||||
String result = inputs.get(position);
|
|
||||||
position++;
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized int getInputCount() {
|
|
||||||
return inputs.size();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue