You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
5.7 KiB

  1. #if NET40 || NET461
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.IO.Compression;
  7. namespace Apewer.Internals.QrCode
  8. {
  9. internal class QRCodeData : IDisposable
  10. {
  11. public List<BitArray> ModuleMatrix { get; set; }
  12. public QRCodeData(int version)
  13. {
  14. this.Version = version;
  15. var size = ModulesPerSideFromVersion(version);
  16. this.ModuleMatrix = new List<BitArray>();
  17. for (var i = 0; i < size; i++)
  18. this.ModuleMatrix.Add(new BitArray(size));
  19. }
  20. #if !PCL
  21. public QRCodeData(string pathToRawData, Compression compressMode) : this(File.ReadAllBytes(pathToRawData), compressMode)
  22. {
  23. }
  24. #endif
  25. public QRCodeData(byte[] rawData, Compression compressMode)
  26. {
  27. var bytes = new List<byte>(rawData);
  28. //Decompress
  29. if (compressMode.Equals(Compression.Deflate))
  30. {
  31. using (var input = new MemoryStream(bytes.ToArray()))
  32. {
  33. using (var output = new MemoryStream())
  34. {
  35. using (var dstream = new DeflateStream(input, CompressionMode.Decompress))
  36. {
  37. Stream4Methods.CopyTo(dstream, output);
  38. }
  39. bytes = new List<byte>(output.ToArray());
  40. }
  41. }
  42. }
  43. else if (compressMode.Equals(Compression.GZip))
  44. {
  45. using (var input = new MemoryStream(bytes.ToArray()))
  46. {
  47. using (var output = new MemoryStream())
  48. {
  49. using (var dstream = new GZipStream(input, CompressionMode.Decompress))
  50. {
  51. Stream4Methods.CopyTo(dstream, output);
  52. }
  53. bytes = new List<byte>(output.ToArray());
  54. }
  55. }
  56. }
  57. if (bytes[0] != 0x51 || bytes[1] != 0x52 || bytes[2] != 0x52)
  58. throw new Exception("Invalid raw data file. Filetype doesn't match \"QRR\".");
  59. //Set QR code version
  60. var sideLen = (int)bytes[4];
  61. bytes.RemoveRange(0, 5);
  62. this.Version = (sideLen - 21 - 8) / 4 + 1;
  63. //Unpack
  64. var modules = new Queue<bool>();
  65. foreach (var b in bytes)
  66. {
  67. var bArr = new BitArray(new byte[] { b });
  68. for (int i = 7; i >= 0; i--)
  69. {
  70. modules.Enqueue((b & (1 << i)) != 0);
  71. }
  72. }
  73. //Build module matrix
  74. this.ModuleMatrix = new List<BitArray>();
  75. for (int y = 0; y < sideLen; y++)
  76. {
  77. this.ModuleMatrix.Add(new BitArray(sideLen));
  78. for (int x = 0; x < sideLen; x++)
  79. {
  80. this.ModuleMatrix[y][x] = modules.Dequeue();
  81. }
  82. }
  83. }
  84. public byte[] GetRawData(Compression compressMode)
  85. {
  86. var bytes = new List<byte>();
  87. //Add header - signature ("QRR")
  88. bytes.AddRange(new byte[]{ 0x51, 0x52, 0x52, 0x00 });
  89. //Add header - rowsize
  90. bytes.Add((byte)ModuleMatrix.Count);
  91. //Build data queue
  92. var dataQueue = new Queue<int>();
  93. foreach (var row in ModuleMatrix)
  94. {
  95. foreach (var module in row)
  96. {
  97. dataQueue.Enqueue((bool)module ? 1 : 0);
  98. }
  99. }
  100. for (int i = 0; i < 8 - (ModuleMatrix.Count * ModuleMatrix.Count) % 8; i++)
  101. {
  102. dataQueue.Enqueue(0);
  103. }
  104. //Process queue
  105. while (dataQueue.Count > 0)
  106. {
  107. byte b = 0;
  108. for (int i = 7; i >= 0; i--)
  109. {
  110. b += (byte)(dataQueue.Dequeue() << i);
  111. }
  112. bytes.Add(b);
  113. }
  114. var rawData = bytes.ToArray();
  115. //Compress stream (optional)
  116. if (compressMode.Equals(Compression.Deflate))
  117. {
  118. using (var output = new MemoryStream())
  119. {
  120. using (var dstream = new DeflateStream(output, CompressionMode.Compress))
  121. {
  122. dstream.Write(rawData, 0, rawData.Length);
  123. }
  124. rawData = output.ToArray();
  125. }
  126. }
  127. else if (compressMode.Equals(Compression.GZip))
  128. {
  129. using (var output = new MemoryStream())
  130. {
  131. using (GZipStream gzipStream = new GZipStream(output, CompressionMode.Compress, true))
  132. {
  133. gzipStream.Write(rawData, 0, rawData.Length);
  134. }
  135. rawData = output.ToArray();
  136. }
  137. }
  138. return rawData;
  139. }
  140. #if !PCL
  141. public void SaveRawData(string filePath, Compression compressMode)
  142. {
  143. File.WriteAllBytes(filePath, GetRawData(compressMode));
  144. }
  145. #endif
  146. public int Version { get; private set; }
  147. private static int ModulesPerSideFromVersion(int version)
  148. {
  149. return 21 + (version - 1) * 4;
  150. }
  151. public void Dispose()
  152. {
  153. this.ModuleMatrix = null;
  154. this.Version = 0;
  155. }
  156. public enum Compression
  157. {
  158. Uncompressed,
  159. Deflate,
  160. GZip
  161. }
  162. }
  163. }
  164. #endif