⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qrcodedecoder.java

📁 qrcode的java开源版本
💻 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 + -