QRCodeDecoder.cs
上传用户:tjjgrl
上传日期:2019-04-04
资源大小:1010k
文件大小:15k
源码类别:

电子政务应用

开发平台:

C#

  1. using System;
  2. using System.Text;
  3. using QRCodeImage = ThoughtWorks.QRCode.Codec.Data.QRCodeImage;
  4. using QRCodeSymbol = ThoughtWorks.QRCode.Codec.Data.QRCodeSymbol;
  5. using ReedSolomon = ThoughtWorks.QRCode.Codec.Ecc.ReedSolomon;
  6. using DecodingFailedException = ThoughtWorks.QRCode.ExceptionHandler.DecodingFailedException;
  7. using InvalidDataBlockException = ThoughtWorks.QRCode.ExceptionHandler.InvalidDataBlockException;
  8. using SymbolNotFoundException = ThoughtWorks.QRCode.ExceptionHandler.SymbolNotFoundException;
  9. using Point = ThoughtWorks.QRCode.Geom.Point;
  10. using QRCodeDataBlockReader = ThoughtWorks.QRCode.Codec.Reader.QRCodeDataBlockReader;
  11. using QRCodeImageReader = ThoughtWorks.QRCode.Codec.Reader.QRCodeImageReader;
  12. using DebugCanvas = ThoughtWorks.QRCode.Codec.Util.DebugCanvas;
  13. using DebugCanvasAdapter = ThoughtWorks.QRCode.Codec.Util.DebugCanvasAdapter;
  14. using QRCodeUtility = ThoughtWorks.QRCode.Codec.Util.QRCodeUtility;
  15. namespace ThoughtWorks.QRCode.Codec
  16. {
  17. public class QRCodeDecoder
  18. {
  19.         internal QRCodeSymbol qrCodeSymbol;
  20.         internal int numTryDecode;
  21.         internal System.Collections.ArrayList results;
  22.         internal System.Collections.ArrayList lastResults = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
  23.         internal static DebugCanvas canvas;
  24.         internal QRCodeImageReader imageReader;
  25.         internal int numLastCorrections;
  26.         internal bool correctionSucceeded;
  27. public static DebugCanvas Canvas
  28. {
  29. get
  30. {
  31. return QRCodeDecoder.canvas;
  32. }
  33. set
  34. {
  35. QRCodeDecoder.canvas = value;
  36. }
  37. }
  38. virtual internal Point[] AdjustPoints
  39. {
  40. get
  41. {
  42. // note that adjusts affect dependently
  43. // i.e. below means (0,0), (2,3), (3,4), (1,2), (2,1), (1,1), (-1,-1)
  44. // Point[] adjusts = {new Point(0,0), new Point(2,3), new Point(1,1), 
  45. // new Point(-2,-2), new Point(1,-1), new Point(-1,0), new Point(-2,-2)};
  46. System.Collections.ArrayList adjustPoints = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
  47. for (int d = 0; d < 4; d++)
  48. adjustPoints.Add(new Point(1, 1));
  49. int lastX = 0, lastY = 0;
  50. for (int y = 0; y > - 4; y--)
  51. {
  52. for (int x = 0; x > - 4; x--)
  53. {
  54. if (x != y && ((x + y) % 2 == 0))
  55. {
  56. adjustPoints.Add(new Point(x - lastX, y - lastY));
  57. lastX = x;
  58. lastY = y;
  59. }
  60. }
  61. }
  62. Point[] adjusts = new Point[adjustPoints.Count];
  63. for (int i = 0; i < adjusts.Length; i++)
  64. adjusts[i] = (Point) adjustPoints[i];
  65. return adjusts;
  66. }
  67. }
  68. internal class DecodeResult
  69. {
  70.             internal int numCorrections;
  71.             internal bool correctionSucceeded;
  72.             internal sbyte[] decodedBytes;
  73.             private QRCodeDecoder enclosingInstance;
  74.             public DecodeResult(QRCodeDecoder enclosingInstance, sbyte[] decodedBytes, int numErrors, bool correctionSucceeded)
  75.             {
  76.                 InitBlock(enclosingInstance);
  77.                 this.decodedBytes = decodedBytes;
  78.                 this.numCorrections = numErrors;
  79.                 this.correctionSucceeded = correctionSucceeded;
  80.             }
  81. private void  InitBlock(QRCodeDecoder enclosingInstance)
  82. {
  83. this.enclosingInstance = enclosingInstance;
  84. }
  85. virtual public sbyte[] DecodedBytes
  86. {
  87. get
  88. {
  89. return decodedBytes;
  90. }
  91. }
  92. virtual public int NumErrors
  93. {
  94. get
  95. {
  96. return numCorrections;
  97. }
  98. }
  99. virtual public bool CorrectionSucceeded
  100. {
  101. get
  102. {
  103. return correctionSucceeded;
  104. }
  105. }
  106. public QRCodeDecoder Enclosing_Instance
  107. {
  108. get
  109. {
  110. return enclosingInstance;
  111. }
  112. }
  113. }
  114. public QRCodeDecoder()
  115. {
  116. numTryDecode = 0;
  117. results = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
  118. QRCodeDecoder.canvas = new DebugCanvasAdapter();
  119. }
  120. /* public byte[] decode(QRCodeImage qrCodeImage) throws DecodingFailedException{
  121.     canvas.println("Decoding started.");
  122.     int[][] intImage = imageToIntArray(qrCodeImage);
  123.     try {
  124.     QRCodeImageReader reader = new QRCodeImageReader();
  125.     qrCodeSymbol = reader.getQRCodeSymbol(intImage);
  126.     } catch (SymbolNotFoundException e) {
  127.     throw new DecodingFailedException(e.getMessage());
  128.     }
  129.     canvas.println("Created QRCode symbol.");
  130.     canvas.println("Reading symbol.");
  131.     canvas.println("Version: " + qrCodeSymbol.getVersionReference());
  132.     canvas.println("Mask pattern: " + qrCodeSymbol.getMaskPatternRefererAsString());
  133.     int[] blocks = qrCodeSymbol.getBlocks();
  134.     canvas.println("Correcting data errors.");
  135.     int[] dataBlocks = correctDataBlocks(blocks);
  136.     try {
  137.     byte[] decodedByteArray = 
  138.     getDecodedByteArray(dataBlocks, qrCodeSymbol.getVersion());
  139.     canvas.println("Decoding finished.");
  140.     return decodedByteArray;
  141.     } catch (InvalidDataBlockException e) {
  142.     throw new DecodingFailedException(e.getMessage());
  143.     }
  144. }*/
  145. public virtual sbyte[] decodeBytes(QRCodeImage qrCodeImage)
  146. {
  147. Point[] adjusts = AdjustPoints;
  148. System.Collections.ArrayList results = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
  149. while (numTryDecode < adjusts.Length)
  150. {
  151. try
  152. {
  153. DecodeResult result = decode(qrCodeImage, adjusts[numTryDecode]);
  154. if (result.CorrectionSucceeded)
  155. {
  156. return result.DecodedBytes;
  157. }
  158. else
  159. {
  160. results.Add(result);
  161. canvas.println("Decoding succeeded but could not correct");
  162. canvas.println("all errors. Retrying..");
  163. }
  164. }
  165. catch (DecodingFailedException dfe)
  166. {
  167. if (dfe.Message.IndexOf("Finder Pattern") >= 0)
  168. throw dfe;
  169. }
  170. finally
  171. {
  172. numTryDecode += 1;
  173. }
  174. }
  175. if (results.Count == 0)
  176. throw new DecodingFailedException("Give up decoding");
  177. int lowestErrorIndex = - 1;
  178. int lowestError = System.Int32.MaxValue;
  179. for (int i = 0; i < results.Count; i++)
  180. {
  181. DecodeResult result = (DecodeResult) results[i];
  182. if (result.NumErrors < lowestError)
  183. {
  184. lowestError = result.NumErrors;
  185. lowestErrorIndex = i;
  186. }
  187. }
  188. canvas.println("All trials need for correct error");
  189. canvas.println("Reporting #" + (lowestErrorIndex) + " that,");
  190. canvas.println("corrected minimum errors (" + lowestError + ")");
  191. canvas.println("Decoding finished.");
  192. return ((DecodeResult) results[lowestErrorIndex]).DecodedBytes;
  193. }
  194.         public virtual String decode(QRCodeImage qrCodeImage, Encoding encoding)
  195.         {
  196.             sbyte[] data = decodeBytes(qrCodeImage);
  197.             byte[] byteData = new byte[data.Length];
  198.             Buffer.BlockCopy(data, 0, byteData, 0, byteData.Length); 
  199.             /*
  200.             char[] decodedData = new char[data.Length];
  201.             for (int i = 0; i < data.Length; i++)
  202.             {
  203.                 decodedData[i] = Convert.to(data[i]);
  204.             }
  205.             return new String(decodedData);
  206.             */
  207.             String decodedData;            
  208.             decodedData = encoding.GetString(byteData);
  209.             return decodedData;
  210.         }
  211.         public virtual String decode(QRCodeImage qrCodeImage)
  212.         {
  213.             sbyte[] data = decodeBytes(qrCodeImage);
  214.             byte[] byteData = new byte[data.Length];
  215.             Buffer.BlockCopy(data, 0, byteData, 0, byteData.Length);
  216.             Encoding encoding;
  217.             if (QRCodeUtility.IsUnicode(byteData))
  218.             {
  219.                 encoding = Encoding.Unicode;
  220.             }
  221.             else
  222.             {
  223.                 encoding = Encoding.ASCII;
  224.             }
  225.             String decodedData;
  226.             decodedData = encoding.GetString(byteData);
  227.             return decodedData;
  228.         }
  229. internal virtual DecodeResult decode(QRCodeImage qrCodeImage, Point adjust)
  230. {
  231. try
  232. {
  233. if (numTryDecode == 0)
  234. {
  235. canvas.println("Decoding started");
  236. int[][] intImage = imageToIntArray(qrCodeImage);
  237. imageReader = new QRCodeImageReader();
  238. qrCodeSymbol = imageReader.getQRCodeSymbol(intImage);
  239. }
  240. else
  241. {
  242. canvas.println("--");
  243. canvas.println("Decoding restarted #" + (numTryDecode));
  244. qrCodeSymbol = imageReader.getQRCodeSymbolWithAdjustedGrid(adjust);
  245. }
  246. }
  247. catch (SymbolNotFoundException e)
  248. {
  249. throw new DecodingFailedException(e.Message);
  250. }
  251. canvas.println("Created QRCode symbol.");
  252. canvas.println("Reading symbol.");
  253. canvas.println("Version: " + qrCodeSymbol.VersionReference);
  254. canvas.println("Mask pattern: " + qrCodeSymbol.MaskPatternRefererAsString);
  255. // blocks contains all (data and RS) blocks in QR Code symbol
  256. int[] blocks = qrCodeSymbol.Blocks;
  257. canvas.println("Correcting data errors.");
  258. // now blocks turn to data blocks (corrected and extracted from original blocks)
  259. blocks = correctDataBlocks(blocks);
  260. try
  261. {
  262. sbyte[] decodedByteArray = getDecodedByteArray(blocks, qrCodeSymbol.Version, qrCodeSymbol.NumErrorCollectionCode);
  263. return new DecodeResult(this, decodedByteArray, numLastCorrections, correctionSucceeded);
  264. }
  265. catch (InvalidDataBlockException e)
  266. {
  267. canvas.println(e.Message);
  268. throw new DecodingFailedException(e.Message);
  269. }
  270. }
  271. internal virtual int[][] imageToIntArray(QRCodeImage image)
  272. {
  273. int width = image.Width;
  274. int height = image.Height;
  275. int[][] intImage = new int[width][];
  276. for (int i = 0; i < width; i++)
  277. {
  278. intImage[i] = new int[height];
  279. }
  280. for (int y = 0; y < height; y++)
  281. {
  282. for (int x = 0; x < width; x++)
  283. {
  284. intImage[x][y] = image.getPixel(x, y);
  285. }
  286. }
  287. return intImage;
  288. }
  289. internal virtual int[] correctDataBlocks(int[] blocks)
  290. {
  291. int numCorrections = 0;
  292. int dataCapacity = qrCodeSymbol.DataCapacity;
  293. int[] dataBlocks = new int[dataCapacity];
  294. int numErrorCollectionCode = qrCodeSymbol.NumErrorCollectionCode;
  295. int numRSBlocks = qrCodeSymbol.NumRSBlocks;
  296. int eccPerRSBlock = numErrorCollectionCode / numRSBlocks;
  297. if (numRSBlocks == 1)
  298. {
  299. ReedSolomon corrector = new ReedSolomon(blocks, eccPerRSBlock);
  300. corrector.correct();
  301. numCorrections += corrector.NumCorrectedErrors;
  302. if (numCorrections > 0)
  303. canvas.println(System.Convert.ToString(numCorrections) + " data errors corrected.");
  304. else
  305. canvas.println("No errors found.");
  306. numLastCorrections = numCorrections;
  307. correctionSucceeded = corrector.CorrectionSucceeded;
  308. return blocks;
  309. }
  310. else
  311. {
  312. //we have to interleave data blocks because symbol has 2 or more RS blocks
  313. int numLongerRSBlocks = dataCapacity % numRSBlocks;
  314. if (numLongerRSBlocks == 0)
  315. {
  316. //symbol has only 1 type of RS block
  317. int lengthRSBlock = dataCapacity / numRSBlocks;
  318. int[][] tmpArray = new int[numRSBlocks][];
  319. for (int i = 0; i < numRSBlocks; i++)
  320. {
  321. tmpArray[i] = new int[lengthRSBlock];
  322. }
  323. int[][] RSBlocks = tmpArray;
  324. //obtain RS blocks
  325. for (int i = 0; i < numRSBlocks; i++)
  326. {
  327. for (int j = 0; j < lengthRSBlock; j++)
  328. {
  329. RSBlocks[i][j] = blocks[j * numRSBlocks + i];
  330. }
  331. ReedSolomon corrector = new ReedSolomon(RSBlocks[i], eccPerRSBlock);
  332. corrector.correct();
  333. numCorrections += corrector.NumCorrectedErrors;
  334. correctionSucceeded = corrector.CorrectionSucceeded;
  335. }
  336. //obtain only data part
  337. int p = 0;
  338. for (int i = 0; i < numRSBlocks; i++)
  339. {
  340. for (int j = 0; j < lengthRSBlock - eccPerRSBlock; j++)
  341. {
  342. dataBlocks[p++] = RSBlocks[i][j];
  343. }
  344. }
  345. }
  346. else
  347. {
  348. //symbol has 2 types of RS blocks
  349. int lengthShorterRSBlock = dataCapacity / numRSBlocks;
  350. int lengthLongerRSBlock = dataCapacity / numRSBlocks + 1;
  351. int numShorterRSBlocks = numRSBlocks - numLongerRSBlocks;
  352. int[][] tmpArray2 = new int[numShorterRSBlocks][];
  353. for (int i2 = 0; i2 < numShorterRSBlocks; i2++)
  354. {
  355. tmpArray2[i2] = new int[lengthShorterRSBlock];
  356. }
  357. int[][] shorterRSBlocks = tmpArray2;
  358. int[][] tmpArray3 = new int[numLongerRSBlocks][];
  359. for (int i3 = 0; i3 < numLongerRSBlocks; i3++)
  360. {
  361. tmpArray3[i3] = new int[lengthLongerRSBlock];
  362. }
  363. int[][] longerRSBlocks = tmpArray3;
  364. for (int i = 0; i < numRSBlocks; i++)
  365. {
  366. if (i < numShorterRSBlocks)
  367. {
  368. //get shorter RS Block(s)
  369. int mod = 0;
  370. for (int j = 0; j < lengthShorterRSBlock; j++)
  371. {
  372. if (j == lengthShorterRSBlock - eccPerRSBlock)
  373. mod = numLongerRSBlocks;
  374. shorterRSBlocks[i][j] = blocks[j * numRSBlocks + i + mod];
  375. }
  376. ReedSolomon corrector = new ReedSolomon(shorterRSBlocks[i], eccPerRSBlock);
  377. corrector.correct();
  378. numCorrections += corrector.NumCorrectedErrors;
  379. correctionSucceeded = corrector.CorrectionSucceeded;
  380. }
  381. else
  382. {
  383. //get longer RS Blocks
  384. int mod = 0;
  385. for (int j = 0; j < lengthLongerRSBlock; j++)
  386. {
  387. if (j == lengthShorterRSBlock - eccPerRSBlock)
  388. mod = numShorterRSBlocks;
  389. longerRSBlocks[i - numShorterRSBlocks][j] = blocks[j * numRSBlocks + i - mod];
  390. }
  391. ReedSolomon corrector = new ReedSolomon(longerRSBlocks[i - numShorterRSBlocks], eccPerRSBlock);
  392. corrector.correct();
  393. numCorrections += corrector.NumCorrectedErrors;
  394. correctionSucceeded = corrector.CorrectionSucceeded;
  395. }
  396. }
  397. int p = 0;
  398. for (int i = 0; i < numRSBlocks; i++)
  399. {
  400. if (i < numShorterRSBlocks)
  401. {
  402. for (int j = 0; j < lengthShorterRSBlock - eccPerRSBlock; j++)
  403. {
  404. dataBlocks[p++] = shorterRSBlocks[i][j];
  405. }
  406. }
  407. else
  408. {
  409. for (int j = 0; j < lengthLongerRSBlock - eccPerRSBlock; j++)
  410. {
  411. dataBlocks[p++] = longerRSBlocks[i - numShorterRSBlocks][j];
  412. }
  413. }
  414. }
  415. }
  416. if (numCorrections > 0)
  417. canvas.println(System.Convert.ToString(numCorrections) + " data errors corrected.");
  418. else
  419. canvas.println("No errors found.");
  420. numLastCorrections = numCorrections;
  421. return dataBlocks;
  422. }
  423. }
  424. internal virtual sbyte[] getDecodedByteArray(int[] blocks, int version, int numErrorCorrectionCode)
  425. {
  426. sbyte[] byteArray;
  427. QRCodeDataBlockReader reader = new QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode);
  428. try
  429. {
  430. byteArray = reader.DataByte;
  431. }
  432. catch (InvalidDataBlockException e)
  433. {
  434. throw e;
  435. }
  436. return byteArray;
  437. }
  438. internal virtual String getDecodedString(int[] blocks, int version, int numErrorCorrectionCode)
  439. {
  440. String dataString = null;
  441. QRCodeDataBlockReader reader = new QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode);
  442. try
  443. {
  444. dataString = reader.DataString;
  445. }
  446. catch (System.IndexOutOfRangeException e)
  447. {
  448. throw new InvalidDataBlockException(e.Message);
  449. }
  450. return dataString;
  451. }
  452.        
  453. }
  454. }