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

Scan and Read the Barcode from PDF File

Rate me:
Please Sign up or sign in to vote.
4.89/5 (30 votes)
5 Aug 2010CPOL4 min read 344K   30.1K   149  
Scan the PDF file and recognize if it contains the Barcode or not
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)
United States United States
Piyush has valuable experience in requirements gathering, designing, implementing, and maintaining data-driven, object-oriented and service based enterprise systems. In addition to his technical expertise, Piyush also published paper on knowledge management and he has excellent communication skills to cooperate with the clients.

He holds a Masters Degree in Computer Science from the University Of Michigan, USA

Comments and Discussions