📄 qrcodedecoder.java
字号:
/*
* created 2004/09/12
*/
package jp.sourceforge.qrcode.codec;
import java.util.Vector;
import jp.sourceforge.qrcode.codec.data.QRCodeImage;
import jp.sourceforge.qrcode.codec.data.QRCodeSymbol;
import jp.sourceforge.qrcode.codec.ecc.ReedSolomon;
import jp.sourceforge.qrcode.codec.exception.DecodingFailedException;
import jp.sourceforge.qrcode.codec.exception.InvalidDataBlockException;
import jp.sourceforge.qrcode.codec.exception.SymbolNotFoundException;
import jp.sourceforge.qrcode.codec.geom.Point;
import jp.sourceforge.qrcode.codec.reader.QRCodeDataBlockReader;
import jp.sourceforge.qrcode.codec.reader.QRCodeImageReader;
import jp.sourceforge.qrcode.codec.util.DebugCanvas;
import jp.sourceforge.qrcode.codec.util.DebugCanvasAdapter;
public class QRCodeDecoder {
QRCodeSymbol qrCodeSymbol;
int numTryDecode;
Vector results;
Vector lastResults = new Vector();
static DebugCanvas canvas;
QRCodeImageReader imageReader;
int numLastCorrections;
boolean correctionSucceeded;
class DecodeResult {
int numCorrections;
boolean correctionSucceeded;
byte[] decodedBytes;
public DecodeResult(byte[] decodedBytes,int numErrors, boolean correctionSucceeded) {
this.decodedBytes = decodedBytes;
this.numCorrections = numErrors;
this.correctionSucceeded = correctionSucceeded;
}
public byte[] getDecodedBytes() {
return decodedBytes;
}
public int getNumErrors() {
return numCorrections;
}
public boolean isCorrectionSucceeded() {
return correctionSucceeded;
}
}
public static void setCanvas(DebugCanvas canvas) {
QRCodeDecoder.canvas = canvas;
}
public static DebugCanvas getCanvas() {
return QRCodeDecoder.canvas;
}
public QRCodeDecoder() {
numTryDecode = 0;
results = new Vector();
QRCodeDecoder.canvas = new DebugCanvasAdapter();
}
/* public byte[] decode(QRCodeImage qrCodeImage) throws DecodingFailedException{
canvas.println("Decoding started.");
int[][] intImage = imageToIntArray(qrCodeImage);
try {
QRCodeImageReader reader = new QRCodeImageReader();
qrCodeSymbol = reader.getQRCodeSymbol(intImage);
} catch (SymbolNotFoundException e) {
throw new DecodingFailedException(e.getMessage());
}
canvas.println("Created QRCode symbol.");
canvas.println("Reading symbol.");
canvas.println("Version: " + qrCodeSymbol.getVersionReference());
canvas.println("Mask pattern: " + qrCodeSymbol.getMaskPatternRefererAsString());
int[] blocks = qrCodeSymbol.getBlocks();
canvas.println("Correcting data errors.");
int[] dataBlocks = correctDataBlocks(blocks);
try {
byte[] decodedByteArray =
getDecodedByteArray(dataBlocks, qrCodeSymbol.getVersion());
canvas.println("Decoding finished.");
return decodedByteArray;
} catch (InvalidDataBlockException e) {
throw new DecodingFailedException(e.getMessage());
}
}*/
public byte[] decode(QRCodeImage qrCodeImage) throws DecodingFailedException{
Point[] adjusts = getAdjustPoints();
Vector results = new Vector();
while (numTryDecode < adjusts.length) {
try {
DecodeResult result = decode(qrCodeImage, adjusts[numTryDecode]);
if (result.isCorrectionSucceeded()) {
return result.getDecodedBytes();
}
else {
results.addElement(result);
canvas.println("Decoding succeeded but could not correct");
canvas.println("all errors. Retrying..");
}
} catch (DecodingFailedException dfe) {
if (dfe.getMessage().indexOf("Finder Pattern") >= 0)
throw dfe;
} finally {
numTryDecode += 1;
}
}
if (results.size() == 0)
throw new DecodingFailedException("Give up decoding");
int lowestErrorIndex = -1;
int lowestError = Integer.MAX_VALUE;
for (int i = 0; i < results.size(); i++) {
DecodeResult result = (DecodeResult)results.elementAt(i);
if (result.getNumErrors() < lowestError) {
lowestError = result.getNumErrors();
lowestErrorIndex = i;
}
}
canvas.println("All trials need for correct error");
canvas.println("Reporting #" + (lowestErrorIndex)+" that,");
canvas.println("corrected minimum errors (" +lowestError + ")");
;
canvas.println("Decoding finished.");
return ((DecodeResult)results.elementAt(lowestErrorIndex)).getDecodedBytes();
}
Point[] getAdjustPoints() {
// note that adjusts affect dependently
// i.e. below means (0,0), (2,3), (3,4), (1,2), (2,1), (1,1), (-1,-1)
// Point[] adjusts = {new Point(0,0), new Point(2,3), new Point(1,1),
// new Point(-2,-2), new Point(1,-1), new Point(-1,0), new Point(-2,-2)};
Vector adjustPoints = new Vector();
for (int d = 0; d < 4; d++)
adjustPoints.addElement(new Point(1, 1));
int lastX = 0, lastY = 0;
for (int y = 0; y > -4; y--) {
for (int x = 0; x > -4; x--) {
if (x != y && ((x+y) % 2 == 0)) {
adjustPoints.addElement(new Point(x-lastX, y-lastY));
lastX = x;
lastY = y;
}
}
}
Point[] adjusts = new Point[adjustPoints.size()];
for (int i = 0; i < adjusts.length; i++)
adjusts[i] = (Point)adjustPoints.elementAt(i);
return adjusts;
}
DecodeResult decode(QRCodeImage qrCodeImage, Point adjust)
throws DecodingFailedException {
try {
if (numTryDecode == 0) {
canvas.println("Decoding started");
int[][] intImage = imageToIntArray(qrCodeImage);
imageReader = new QRCodeImageReader();
qrCodeSymbol = imageReader.getQRCodeSymbol(intImage);
} else {
canvas.println("--");
canvas.println("Decoding restarted #" + (numTryDecode));
qrCodeSymbol = imageReader.getQRCodeSymbolWithAdjustedGrid(adjust);
}
} catch (SymbolNotFoundException e) {
throw new DecodingFailedException(e.getMessage());
}
canvas.println("Created QRCode symbol.");
canvas.println("Reading symbol.");
canvas.println("Version: " + qrCodeSymbol.getVersionReference());
canvas.println("Mask pattern: " + qrCodeSymbol.getMaskPatternRefererAsString());
// blocks contains all (data and RS) blocks in QR Code symbol
int[] blocks = qrCodeSymbol.getBlocks();
canvas.println("Correcting data errors.");
// now blocks turn to data blocks (corrected and extracted from original blocks)
blocks = correctDataBlocks(blocks);
try {
byte[] decodedByteArray =
getDecodedByteArray(blocks, qrCodeSymbol.getVersion(), qrCodeSymbol.getNumErrorCollectionCode());
return new DecodeResult(decodedByteArray, numLastCorrections, correctionSucceeded);
} catch (InvalidDataBlockException e) {
canvas.println(e.getMessage());
throw new DecodingFailedException(e.getMessage());
}
}
int[][] imageToIntArray(QRCodeImage image) {
int width = image.getWidth();
int height = image.getHeight();
int[][] intImage = new int[width][height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
intImage[x][y] = image.getPixel(x,y);
}
}
return intImage;
}
int[] correctDataBlocks(int[] blocks) {
int numCorrections = 0;
int dataCapacity = qrCodeSymbol.getDataCapacity();
int[] dataBlocks = new int[dataCapacity];
int numErrorCollectionCode = qrCodeSymbol.getNumErrorCollectionCode();
int numRSBlocks = qrCodeSymbol.getNumRSBlocks();
int eccPerRSBlock = numErrorCollectionCode / numRSBlocks;
if (numRSBlocks == 1) {
ReedSolomon corrector = new ReedSolomon(blocks, eccPerRSBlock);
corrector.correct();
numCorrections += corrector.getNumCorrectedErrors();
if (numCorrections > 0)
canvas.println(String.valueOf(numCorrections) + " data errors corrected.");
else
canvas.println("No errors found.");
numLastCorrections = numCorrections;
correctionSucceeded = corrector.isCorrectionSucceeded();
return blocks;
}
else { //we have to interleave data blocks because symbol has 2 or more RS blocks
int numLongerRSBlocks = dataCapacity % numRSBlocks;
if (numLongerRSBlocks == 0) { //symbol has only 1 type of RS block
int lengthRSBlock = dataCapacity / numRSBlocks;
int[][] RSBlocks = new int[numRSBlocks][lengthRSBlock];
//obtain RS blocks
for (int i = 0; i < numRSBlocks; i++) {
for (int j = 0; j < lengthRSBlock; j++) {
RSBlocks[i][j] = blocks[j * numRSBlocks + i];
}
ReedSolomon corrector = new ReedSolomon(RSBlocks[i], eccPerRSBlock);
corrector.correct();
numCorrections += corrector.getNumCorrectedErrors();
correctionSucceeded = corrector.isCorrectionSucceeded();
}
//obtain only data part
int p = 0;
for (int i = 0; i < numRSBlocks; i++) {
for (int j = 0; j < lengthRSBlock - eccPerRSBlock; j++) {
dataBlocks[p++] = RSBlocks[i][j];
}
}
}
else { //symbol has 2 types of RS blocks
int lengthShorterRSBlock = dataCapacity / numRSBlocks;
int lengthLongerRSBlock = dataCapacity / numRSBlocks + 1;
int numShorterRSBlocks = numRSBlocks - numLongerRSBlocks;
int[][] shorterRSBlocks = new int[numShorterRSBlocks][lengthShorterRSBlock];
int[][] longerRSBlocks = new int[numLongerRSBlocks][lengthLongerRSBlock];
for (int i = 0; i < numRSBlocks; i++) {
if (i < numShorterRSBlocks) { //get shorter RS Block(s)
int mod = 0;
for (int j = 0; j < lengthShorterRSBlock; j++) {
if (j == lengthShorterRSBlock - eccPerRSBlock) mod = numLongerRSBlocks;
shorterRSBlocks[i][j] = blocks[j * numRSBlocks + i + mod];
}
ReedSolomon corrector = new ReedSolomon(shorterRSBlocks[i], eccPerRSBlock);
corrector.correct();
numCorrections += corrector.getNumCorrectedErrors();
correctionSucceeded = corrector.isCorrectionSucceeded();
}
else { //get longer RS Blocks
int mod = 0;
for (int j = 0; j < lengthLongerRSBlock; j++) {
if (j == lengthShorterRSBlock - eccPerRSBlock) mod = numShorterRSBlocks;
longerRSBlocks[i - numShorterRSBlocks][j] = blocks[j * numRSBlocks + i - mod];
}
ReedSolomon corrector = new ReedSolomon(longerRSBlocks[i - numShorterRSBlocks], eccPerRSBlock);
corrector.correct();
numCorrections += corrector.getNumCorrectedErrors();
correctionSucceeded = corrector.isCorrectionSucceeded();
}
}
int p = 0;
for (int i = 0; i < numRSBlocks; i++) {
if (i < numShorterRSBlocks) {
for (int j = 0; j < lengthShorterRSBlock - eccPerRSBlock; j++) {
dataBlocks[p++] = shorterRSBlocks[i][j];
}
}
else {
for (int j = 0; j < lengthLongerRSBlock - eccPerRSBlock; j++) {
dataBlocks[p++] = longerRSBlocks[i - numShorterRSBlocks][j];
}
}
}
}
if (numCorrections > 0)
canvas.println(String.valueOf(numCorrections) + " data errors corrected.");
else
canvas.println("No errors found.");
numLastCorrections = numCorrections;
return dataBlocks;
}
}
byte[] getDecodedByteArray(int[] blocks, int version, int numErrorCorrectionCode) throws InvalidDataBlockException {
byte[] byteArray;
QRCodeDataBlockReader reader = new QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode);
try {
byteArray = reader.getDataByte();
} catch (InvalidDataBlockException e) {
throw e;
}
return byteArray;
}
String getDecodedString(int[] blocks, int version, int numErrorCorrectionCode) throws InvalidDataBlockException {
String dataString = null;
QRCodeDataBlockReader reader = new QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode);
try {
dataString = reader.getDataString();
} catch (ArrayIndexOutOfBoundsException e) {
throw new InvalidDataBlockException(e.getMessage());
}
return dataString;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -