Click here to Skip to main content
15,881,881 members
Articles / Programming Languages / C#

Open Source QRCode Library

Rate me:
Please Sign up or sign in to vote.
4.92/5 (147 votes)
20 Sep 2007CPOL1 min read 5.9M   192.2K   421  
How to use QRCode library to encode and decode QRCode
using System;
using QRCodeDecoder = ThoughtWorks.QRCode.Codec.QRCodeDecoder;
using InvalidDataBlockException = ThoughtWorks.QRCode.ExceptionHandler.InvalidDataBlockException;
using DebugCanvas = ThoughtWorks.QRCode.Codec.Util.DebugCanvas;
using SystemUtils = ThoughtWorks.QRCode.Codec.Util.SystemUtils;
namespace ThoughtWorks.QRCode.Codec.Reader
{
	
	public class QRCodeDataBlockReader
	{
		virtual internal int NextMode
		{
			get
			{
				//canvas.println("data blocks:"+ (blocks.length - numErrorCorrectionCode));
				if ((blockPointer > blocks.Length - numErrorCorrectionCode - 2))
					return 0;
				else
					return getNextBits(4);
			}
			
		}
		virtual public sbyte[] DataByte
		{
			get
			{
				canvas.println("Reading data blocks.");
				System.IO.MemoryStream output = new System.IO.MemoryStream();
				
				try
				{
					do 
					{
						int mode = NextMode;
						//canvas.println("mode: " + mode);
						if (mode == 0)
						{
							if (output.Length > 0)
								break;
							else
								throw new InvalidDataBlockException("Empty data block");
						}
						//if (mode != 1 && mode != 2 && mode != 4 && mode != 8)
						//	break;
						//}
						if (mode != MODE_NUMBER && mode != MODE_ROMAN_AND_NUMBER && mode != MODE_8BIT_BYTE && mode != MODE_KANJI)
						{
							/*					canvas.println("Invalid mode: " + mode);
							mode = guessMode(mode);
							canvas.println("Guessed mode: " + mode); */
							throw new InvalidDataBlockException("Invalid mode: " + mode + " in (block:" + blockPointer + " bit:" + bitPointer + ")");
						}
						dataLength = getDataLength(mode);
						if (dataLength < 1)
							throw new InvalidDataBlockException("Invalid data length: " + dataLength);
						//canvas.println("length: " + dataLength);
						switch (mode)
						{
							
							case MODE_NUMBER: 
								//canvas.println("Mode: Figure");
								sbyte[] temp_sbyteArray;
								temp_sbyteArray = SystemUtils.ToSByteArray(SystemUtils.ToByteArray(getFigureString(dataLength)));
								output.Write(SystemUtils.ToByteArray(temp_sbyteArray), 0, temp_sbyteArray.Length);
								break;
							
							case MODE_ROMAN_AND_NUMBER: 
								//canvas.println("Mode: Roman&Figure");
								sbyte[] temp_sbyteArray2;
								temp_sbyteArray2 = SystemUtils.ToSByteArray(SystemUtils.ToByteArray(getRomanAndFigureString(dataLength)));
								output.Write(SystemUtils.ToByteArray(temp_sbyteArray2), 0, temp_sbyteArray2.Length);
								break;
							
							case MODE_8BIT_BYTE: 
								//canvas.println("Mode: 8bit Byte");
								sbyte[] temp_sbyteArray3;
								temp_sbyteArray3 = get8bitByteArray(dataLength);
								output.Write(SystemUtils.ToByteArray(temp_sbyteArray3), 0, temp_sbyteArray3.Length);
								break;
							
							case MODE_KANJI: 
								//canvas.println("Mode: Kanji");
								sbyte[] temp_sbyteArray4;
								temp_sbyteArray4 = SystemUtils.ToSByteArray(SystemUtils.ToByteArray(getKanjiString(dataLength)));
								output.Write(SystemUtils.ToByteArray(temp_sbyteArray4), 0, temp_sbyteArray4.Length);
								break;
							}
						//			
						//canvas.println("DataLength: " + dataLength);
						//Console.out.println(dataString);
					}
					while (true);
				}
				catch (System.IndexOutOfRangeException e)
				{
					SystemUtils.WriteStackTrace(e, Console.Error);
					throw new InvalidDataBlockException("Data Block Error in (block:" + blockPointer + " bit:" + bitPointer + ")");
				}
				catch (System.IO.IOException e)
				{
					throw new InvalidDataBlockException(e.Message);
				}
				return SystemUtils.ToSByteArray(output.ToArray());
			}
			
		}
		virtual public String DataString
		{
			get
			{
				canvas.println("Reading data blocks...");
				String dataString = "";
				do 
				{
					int mode = NextMode;
					canvas.println("mode: " + mode);
					if (mode == 0)
						break;
					//if (mode != 1 && mode != 2 && mode != 4 && mode != 8)
					//	break;
					//}
					if (mode != MODE_NUMBER && mode != MODE_ROMAN_AND_NUMBER && mode != MODE_8BIT_BYTE && mode != MODE_KANJI)
					{
						// mode = guessMode(mode);
						// do not guesswork
						//Console.out.println("guessed mode: " + mode);
					}
					
					dataLength = getDataLength(mode);
					canvas.println(System.Convert.ToString(blocks[blockPointer]));
					System.Console.Out.WriteLine("length: " + dataLength);
					switch (mode)
					{
						
						case MODE_NUMBER: 
							//canvas.println("Mode: Figure");
							dataString += getFigureString(dataLength);
							break;
						
						case MODE_ROMAN_AND_NUMBER: 
							//canvas.println("Mode: Roman&Figure");
							dataString += getRomanAndFigureString(dataLength);
							break;
						
						case MODE_8BIT_BYTE: 
							//canvas.println("Mode: 8bit Byte");
							dataString += get8bitByteString(dataLength);
							break;
						
						case MODE_KANJI: 
							//canvas.println("Mode: Kanji");
							dataString += getKanjiString(dataLength);
							break;
						}
					//canvas.println("DataLength: " + dataLength);
					//Console.out.println(dataString);
				}
				while (true);
				System.Console.Out.WriteLine("");
				return dataString;
			}
			
		}
		internal int[] blocks;
		internal int dataLengthMode;
		internal int blockPointer;
		internal int bitPointer;
		internal int dataLength;
		internal int numErrorCorrectionCode;
		internal DebugCanvas canvas;
	
		const  int MODE_NUMBER = 1;
	    const int MODE_ROMAN_AND_NUMBER = 2;
	    const int MODE_8BIT_BYTE = 4;
	    const int MODE_KANJI = 8;
	    int[][] sizeOfDataLengthInfo = new int[][] { new int[] { 10, 9, 8, 8 }, new int[] { 12, 11, 16, 10 }, new int[] { 14, 13, 16, 12 } };
		
		public QRCodeDataBlockReader(int[] blocks, int version, int numErrorCorrectionCode)
		{
			blockPointer = 0;
			bitPointer = 7;
			dataLength = 0;
			this.blocks = blocks;
			this.numErrorCorrectionCode = numErrorCorrectionCode;
			if (version <= 9)
				dataLengthMode = 0;
			else if (version >= 10 && version <= 26)
				dataLengthMode = 1;
			else if (version >= 27 && version <= 40)
				dataLengthMode = 2;
			canvas = QRCodeDecoder.Canvas;
		}
		
		internal virtual int getNextBits(int numBits)
		{			
			int bits = 0;
			if (numBits < bitPointer + 1)
			{
				// next word fits into current data block
				int mask = 0;
				for (int i = 0; i < numBits; i++)
				{
					mask += (1 << i);
				}
				mask <<= (bitPointer - numBits + 1);
				
				bits = (blocks[blockPointer] & mask) >> (bitPointer - numBits + 1);
				bitPointer -= numBits;
				return bits;
			}
			else if (numBits < bitPointer + 1 + 8)
			{
				// next word crosses 2 data blocks
				int mask1 = 0;
				for (int i = 0; i < bitPointer + 1; i++)
				{
					mask1 += (1 << i);
				}
				bits = (blocks[blockPointer] & mask1) << (numBits - (bitPointer + 1));
                blockPointer++;
				bits += ((blocks[blockPointer]) >> (8 - (numBits - (bitPointer + 1))));
				
				bitPointer = bitPointer - numBits % 8;
				if (bitPointer < 0)
				{
					bitPointer = 8 + bitPointer;
				}
				return bits;
			}
			else if (numBits < bitPointer + 1 + 16)
			{
				// next word crosses 3 data blocks
				int mask1 = 0; // mask of first block
				int mask3 = 0; // mask of 3rd block
				//bitPointer + 1 : number of bits of the 1st block
				//8 : number of the 2nd block (note that use already 8bits because next word uses 3 data blocks)
				//numBits - (bitPointer + 1 + 8) : number of bits of the 3rd block 
				for (int i = 0; i < bitPointer + 1; i++)
				{
					mask1 += (1 << i);
				}
				int bitsFirstBlock = (blocks[blockPointer] & mask1) << (numBits - (bitPointer + 1));
				blockPointer++;
				
				int bitsSecondBlock = blocks[blockPointer] << (numBits - (bitPointer + 1 + 8));
				blockPointer++;
				
				for (int i = 0; i < numBits - (bitPointer + 1 + 8); i++)
				{
					mask3 += (1 << i);
				}
				mask3 <<= 8 - (numBits - (bitPointer + 1 + 8));
				int bitsThirdBlock = (blocks[blockPointer] & mask3) >> (8 - (numBits - (bitPointer + 1 + 8)));
				
				bits = bitsFirstBlock + bitsSecondBlock + bitsThirdBlock;
				bitPointer = bitPointer - (numBits - 8) % 8;
				if (bitPointer < 0)
				{
					bitPointer = 8 + bitPointer;
				}
				return bits;
			}
			else
			{
				System.Console.Out.WriteLine("ERROR!");
				return 0;
			}
		}
		
		internal virtual int guessMode(int mode)
		{
			//correct modes: 0001 0010 0100 1000
			//possible data: 0000 0011 0101 1001 0110 1010 1100
			//               0111 1101 1011 1110 1111
			//		MODE_NUMBER = 1;
			//		MODE_ROMAN_AND_NUMBER = 2;
			//		MODE_8BIT_BYTE = 4;
			//		MODE_KANJI = 8;
			switch (mode)
			{
				
				case 3: 
					return MODE_NUMBER;
				
				case 5: 
					return MODE_8BIT_BYTE;
				
				case 6: 
					return MODE_8BIT_BYTE;
				
				case 7: 
					return MODE_8BIT_BYTE;
				
				case 9: 
					return MODE_KANJI;
				
				case 10: 
					return MODE_KANJI;
				
				case 11: 
					return MODE_KANJI;
				
				case 12: 
					return MODE_8BIT_BYTE;
				
				case 13: 
					return MODE_8BIT_BYTE;
				
				case 14: 
					return MODE_8BIT_BYTE;
				
				case 15: 
					return MODE_8BIT_BYTE;
				
				default: 
					return MODE_KANJI;
				
			}
		}
		
		internal virtual int getDataLength(int modeIndicator)
		{
			int index = 0;
			while (true)
			{
				if ((modeIndicator >> index) == 1)
					break;
				index++;
			}
			
			return getNextBits(sizeOfDataLengthInfo[dataLengthMode][index]);
		}
		
		
		internal virtual String getFigureString(int dataLength)
		{
			int length = dataLength;
			int intData = 0;
			String strData = "";
			do 
			{
				if (length >= 3)
				{
					intData = getNextBits(10);
					if (intData < 100)
						strData += "0";
					if (intData < 10)
						strData += "0";
					length -= 3;
				}
				else if (length == 2)
				{
					intData = getNextBits(7);
					if (intData < 10)
						strData += "0";
					length -= 2;
				}
				else if (length == 1)
				{
					intData = getNextBits(4);
					length -= 1;
				}
				strData += System.Convert.ToString(intData);
			}
			while (length > 0);
			
			return strData;
		}
		
		internal virtual String getRomanAndFigureString(int dataLength)
		{
			int length = dataLength;
			int intData = 0;
			String strData = "";
			char[] tableRomanAndFigure = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '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', ' ', '$', '%', '*', '+', '-', '.', '/', ':'};
			do 
			{
				if (length > 1)
				{
					intData = getNextBits(11);
					int firstLetter = intData / 45;
					int secondLetter = intData % 45;
					strData += System.Convert.ToString(tableRomanAndFigure[firstLetter]);
					strData += System.Convert.ToString(tableRomanAndFigure[secondLetter]);
					length -= 2;
				}
				else if (length == 1)
				{
					intData = getNextBits(6);
					strData += System.Convert.ToString(tableRomanAndFigure[intData]);
					length -= 1;
				}
			}
			while (length > 0);
			
			return strData;
		}
		
		public virtual sbyte[] get8bitByteArray(int dataLength)
		{
			int length = dataLength;
			int intData = 0;
			System.IO.MemoryStream output = new System.IO.MemoryStream();
			
			do 
			{
                canvas.println("Length: " + length);
				intData = getNextBits(8);
				output.WriteByte((byte) intData);
				length--;
			}
			while (length > 0);
			return SystemUtils.ToSByteArray(output.ToArray());
		}
		
		internal virtual String get8bitByteString(int dataLength)
		{
			int length = dataLength;
			int intData = 0;
			String strData = "";
			do 
			{
				intData = getNextBits(8);
				strData += (char) intData;
				length--;
			}
			while (length > 0);
			return strData;
		}
		
		internal virtual String getKanjiString(int dataLength)
		{
			int length = dataLength;
			int intData = 0;
			String unicodeString = "";
			do 
			{
				intData = getNextBits(13);
				int lowerByte = intData % 0xC0;
				int higherByte = intData / 0xC0;
				
				int tempWord = (higherByte << 8) + lowerByte;
				int shiftjisWord = 0;
				if (tempWord + 0x8140 <= 0x9FFC)
				{
					// between 8140 - 9FFC on Shift_JIS character set
					shiftjisWord = tempWord + 0x8140;
				}
				else
				{
					// between E040 - EBBF on Shift_JIS character set
					shiftjisWord = tempWord + 0xC140;
				}
				
				sbyte[] tempByte = new sbyte[2];
				tempByte[0] = (sbyte) (shiftjisWord >> 8);
				tempByte[1] = (sbyte) (shiftjisWord & 0xFF);
				unicodeString += new String(SystemUtils.ToCharArray(SystemUtils.ToByteArray(tempByte)));
				length--;
			}
			while (length > 0);
			
			
			return unicodeString;
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Malaysia Malaysia
A programmer for a long time, and still learning everyday.

A supporter for open source solutions, and have written quite a few open source software both in .NET and Java.

https://mengwangk.github.io/

Comments and Discussions