www.pudn.com > QRCodeLib.rar > QRCodeDecoder.cs, change:2007-08-01,size:15507b


using System; 
using System.Text; 
 
using QRCodeImage = ThoughtWorks.QRCode.Codec.Data.QRCodeImage; 
using QRCodeSymbol = ThoughtWorks.QRCode.Codec.Data.QRCodeSymbol; 
using ReedSolomon = ThoughtWorks.QRCode.Codec.Ecc.ReedSolomon; 
using DecodingFailedException = ThoughtWorks.QRCode.ExceptionHandler.DecodingFailedException; 
using InvalidDataBlockException = ThoughtWorks.QRCode.ExceptionHandler.InvalidDataBlockException; 
using SymbolNotFoundException = ThoughtWorks.QRCode.ExceptionHandler.SymbolNotFoundException; 
using Point = ThoughtWorks.QRCode.Geom.Point; 
using QRCodeDataBlockReader = ThoughtWorks.QRCode.Codec.Reader.QRCodeDataBlockReader; 
using QRCodeImageReader = ThoughtWorks.QRCode.Codec.Reader.QRCodeImageReader; 
using DebugCanvas = ThoughtWorks.QRCode.Codec.Util.DebugCanvas; 
using DebugCanvasAdapter = ThoughtWorks.QRCode.Codec.Util.DebugCanvasAdapter; 
using QRCodeUtility = ThoughtWorks.QRCode.Codec.Util.QRCodeUtility; 
 
namespace ThoughtWorks.QRCode.Codec 
{ 
	 
	public class QRCodeDecoder 
	{ 
        internal QRCodeSymbol qrCodeSymbol; 
        internal int numTryDecode; 
        internal System.Collections.ArrayList results; 
        internal System.Collections.ArrayList lastResults = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); 
        internal static DebugCanvas canvas; 
        internal QRCodeImageReader imageReader; 
        internal int numLastCorrections; 
        internal bool correctionSucceeded; 
 
		public static DebugCanvas Canvas 
		{ 
			get 
			{ 
				return QRCodeDecoder.canvas; 
			} 
			 
			set 
			{ 
				QRCodeDecoder.canvas = value; 
			} 
			 
		} 
		virtual internal Point[] AdjustPoints 
		{ 
			get 
			{ 
				// 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)}; 
				System.Collections.ArrayList adjustPoints = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); 
				for (int d = 0; d < 4; d++) 
					adjustPoints.Add(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.Add(new Point(x - lastX, y - lastY)); 
							lastX = x; 
							lastY = y; 
						} 
					} 
				} 
				Point[] adjusts = new Point[adjustPoints.Count]; 
				for (int i = 0; i < adjusts.Length; i++) 
					adjusts[i] = (Point) adjustPoints[i]; 
				return adjusts; 
			}			 
		}		 
				 
		internal class DecodeResult 
		{ 
            internal int numCorrections; 
            internal bool correctionSucceeded; 
            internal sbyte[] decodedBytes; 
            private QRCodeDecoder enclosingInstance; 
 
            public DecodeResult(QRCodeDecoder enclosingInstance, sbyte[] decodedBytes, int numErrors, bool correctionSucceeded) 
            { 
                InitBlock(enclosingInstance); 
                this.decodedBytes = decodedBytes; 
                this.numCorrections = numErrors; 
                this.correctionSucceeded = correctionSucceeded; 
            } 
 
			private void  InitBlock(QRCodeDecoder enclosingInstance) 
			{ 
				this.enclosingInstance = enclosingInstance; 
			} 
 
			virtual public sbyte[] DecodedBytes 
			{ 
				get 
				{ 
					return decodedBytes; 
				} 
				 
			} 
			virtual public int NumErrors 
			{ 
				get 
				{ 
					return numCorrections; 
				} 
				 
			} 
			virtual public bool CorrectionSucceeded 
			{ 
				get 
				{ 
					return correctionSucceeded; 
				} 
				 
			} 
			public QRCodeDecoder Enclosing_Instance 
			{ 
				get 
				{ 
					return enclosingInstance; 
				} 
				 
			} 
			 
		} 
		 
		public QRCodeDecoder() 
		{ 
			numTryDecode = 0; 
			results = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); 
			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 virtual sbyte[] decodeBytes(QRCodeImage qrCodeImage) 
		{ 
			Point[] adjusts = AdjustPoints; 
			System.Collections.ArrayList results = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); 
			while (numTryDecode < adjusts.Length) 
			{ 
				try 
				{ 
					DecodeResult result = decode(qrCodeImage, adjusts[numTryDecode]); 
					if (result.CorrectionSucceeded) 
					{ 
						return result.DecodedBytes; 
					} 
					else 
					{ 
						results.Add(result); 
						canvas.println("Decoding succeeded but could not correct"); 
						canvas.println("all errors. Retrying.."); 
					} 
				} 
				catch (DecodingFailedException dfe) 
				{ 
					if (dfe.Message.IndexOf("Finder Pattern") >= 0) 
					throw dfe; 
				} 
				finally 
				{ 
					numTryDecode += 1; 
				} 
			} 
			 
			if (results.Count == 0) 
				throw new DecodingFailedException("Give up decoding"); 
			 
			int lowestErrorIndex = - 1; 
			int lowestError = System.Int32.MaxValue; 
			for (int i = 0; i < results.Count; i++) 
			{ 
				DecodeResult result = (DecodeResult) results[i]; 
				if (result.NumErrors < lowestError) 
				{ 
					lowestError = result.NumErrors; 
					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[lowestErrorIndex]).DecodedBytes; 
		} 
 
        public virtual String decode(QRCodeImage qrCodeImage, Encoding encoding) 
        { 
            sbyte[] data = decodeBytes(qrCodeImage); 
            byte[] byteData = new byte[data.Length]; 
 
            Buffer.BlockCopy(data, 0, byteData, 0, byteData.Length);  
            /* 
            char[] decodedData = new char[data.Length]; 
            for (int i = 0; i < data.Length; i++) 
            { 
                decodedData[i] = Convert.to(data[i]); 
 
            } 
            return new String(decodedData); 
            */ 
            String decodedData;             
            decodedData = encoding.GetString(byteData); 
            return decodedData; 
        } 
 
        public virtual String decode(QRCodeImage qrCodeImage) 
        { 
            sbyte[] data = decodeBytes(qrCodeImage); 
            byte[] byteData = new byte[data.Length]; 
            Buffer.BlockCopy(data, 0, byteData, 0, byteData.Length); 
 
            Encoding encoding; 
            if (QRCodeUtility.IsUnicode(byteData)) 
            { 
                encoding = Encoding.Unicode; 
            } 
            else 
            { 
                encoding = Encoding.ASCII; 
            } 
            String decodedData; 
            decodedData = encoding.GetString(byteData); 
            return decodedData; 
        } 
 
		internal virtual DecodeResult decode(QRCodeImage qrCodeImage, Point adjust) 
		{ 
			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.Message); 
			} 
			canvas.println("Created QRCode symbol."); 
			canvas.println("Reading symbol."); 
			canvas.println("Version: " + qrCodeSymbol.VersionReference); 
			canvas.println("Mask pattern: " + qrCodeSymbol.MaskPatternRefererAsString); 
			// blocks contains all (data and RS) blocks in QR Code symbol 
			int[] blocks = qrCodeSymbol.Blocks; 
			canvas.println("Correcting data errors."); 
			// now blocks turn to data blocks (corrected and extracted from original blocks) 
			blocks = correctDataBlocks(blocks); 
			try 
			{ 
				sbyte[] decodedByteArray = getDecodedByteArray(blocks, qrCodeSymbol.Version, qrCodeSymbol.NumErrorCollectionCode); 
				return new DecodeResult(this, decodedByteArray, numLastCorrections, correctionSucceeded); 
			} 
			catch (InvalidDataBlockException e) 
			{ 
				canvas.println(e.Message); 
				throw new DecodingFailedException(e.Message); 
			} 
		} 
		 
		 
		internal virtual int[][] imageToIntArray(QRCodeImage image) 
		{ 
			int width = image.Width; 
			int height = image.Height; 
			int[][] intImage = new int[width][]; 
			for (int i = 0; i < width; i++) 
			{ 
				intImage[i] = new int[height]; 
			} 
			for (int y = 0; y < height; y++) 
			{ 
				for (int x = 0; x < width; x++) 
				{ 
					intImage[x][y] = image.getPixel(x, y); 
				} 
			} 
			return intImage; 
		} 
		 
		internal virtual int[] correctDataBlocks(int[] blocks) 
		{ 
			int numCorrections = 0; 
			int dataCapacity = qrCodeSymbol.DataCapacity; 
			int[] dataBlocks = new int[dataCapacity]; 
			int numErrorCollectionCode = qrCodeSymbol.NumErrorCollectionCode; 
			int numRSBlocks = qrCodeSymbol.NumRSBlocks; 
			int eccPerRSBlock = numErrorCollectionCode / numRSBlocks; 
			if (numRSBlocks == 1) 
			{ 
				ReedSolomon corrector = new ReedSolomon(blocks, eccPerRSBlock); 
				corrector.correct(); 
				numCorrections += corrector.NumCorrectedErrors; 
				if (numCorrections > 0) 
					canvas.println(System.Convert.ToString(numCorrections) + " data errors corrected."); 
				else 
					canvas.println("No errors found."); 
				numLastCorrections = numCorrections; 
				correctionSucceeded = corrector.CorrectionSucceeded; 
				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[][] tmpArray = new int[numRSBlocks][]; 
					for (int i = 0; i < numRSBlocks; i++) 
					{ 
						tmpArray[i] = new int[lengthRSBlock]; 
					} 
					int[][] RSBlocks = tmpArray; 
					//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.NumCorrectedErrors; 
						correctionSucceeded = corrector.CorrectionSucceeded; 
					} 
					//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[][] tmpArray2 = new int[numShorterRSBlocks][]; 
					for (int i2 = 0; i2 < numShorterRSBlocks; i2++) 
					{ 
						tmpArray2[i2] = new int[lengthShorterRSBlock]; 
					} 
					int[][] shorterRSBlocks = tmpArray2; 
					int[][] tmpArray3 = new int[numLongerRSBlocks][]; 
					for (int i3 = 0; i3 < numLongerRSBlocks; i3++) 
					{ 
						tmpArray3[i3] = new int[lengthLongerRSBlock]; 
					} 
					int[][] longerRSBlocks = tmpArray3; 
					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.NumCorrectedErrors; 
							correctionSucceeded = corrector.CorrectionSucceeded; 
						} 
						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.NumCorrectedErrors; 
							correctionSucceeded = corrector.CorrectionSucceeded; 
						} 
					} 
					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(System.Convert.ToString(numCorrections) + " data errors corrected."); 
				else 
					canvas.println("No errors found."); 
				numLastCorrections = numCorrections; 
				return dataBlocks; 
			} 
		} 
		 
		internal virtual sbyte[] getDecodedByteArray(int[] blocks, int version, int numErrorCorrectionCode) 
		{ 
			sbyte[] byteArray; 
			QRCodeDataBlockReader reader = new QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode); 
			try 
			{ 
				byteArray = reader.DataByte; 
			} 
			catch (InvalidDataBlockException e) 
			{ 
				throw e; 
			} 
			return byteArray; 
		} 
		 
		internal virtual String getDecodedString(int[] blocks, int version, int numErrorCorrectionCode) 
		{ 
			String dataString = null; 
			QRCodeDataBlockReader reader = new QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode); 
			try 
			{ 
				dataString = reader.DataString; 
			} 
			catch (System.IndexOutOfRangeException e) 
			{ 
				throw new InvalidDataBlockException(e.Message); 
			} 
			return dataString; 
		} 
 
        
	} 
}