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

QRCodeReader.cs 8.8 kB

10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * Copyright 2007 ZXing authors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. using System;
  17. using System.Collections.Generic;
  18. using ZXing.Common;
  19. using ZXing.QrCode.Internal;
  20. namespace ZXing.QrCode
  21. {
  22. /// <summary>
  23. /// This implementation can detect and decode QR Codes in an image.
  24. /// <author>Sean Owen</author>
  25. /// </summary>
  26. public class QRCodeReader
  27. {
  28. private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0];
  29. private readonly Decoder decoder = new Decoder();
  30. /// <summary>
  31. /// Gets the decoder.
  32. /// </summary>
  33. /// <returns></returns>
  34. protected Decoder getDecoder()
  35. {
  36. return decoder;
  37. }
  38. /// <summary>
  39. /// Locates and decodes a QR code in an image.
  40. ///
  41. /// <returns>a String representing the content encoded by the QR code</returns>
  42. /// </summary>
  43. public Result decode(BinaryBitmap image)
  44. {
  45. return decode(image, null);
  46. }
  47. /// <summary>
  48. /// Locates and decodes a barcode in some format within an image. This method also accepts
  49. /// hints, each possibly associated to some data, which may help the implementation decode.
  50. /// </summary>
  51. /// <param name="image">image of barcode to decode</param>
  52. /// <param name="hints">passed as a <see cref="IDictionary{TKey, TValue}"/> from <see cref="DecodeHintType"/>
  53. /// to arbitrary data. The
  54. /// meaning of the data depends upon the hint type. The implementation may or may not do
  55. /// anything with these hints.</param>
  56. /// <returns>
  57. /// String which the barcode encodes
  58. /// </returns>
  59. public Result decode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints)
  60. {
  61. DecoderResult decoderResult;
  62. ResultPoint[] points;
  63. if (image == null || image.BlackMatrix == null)
  64. {
  65. // something is wrong with the image
  66. return null;
  67. }
  68. if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE))
  69. {
  70. var bits = extractPureBits(image.BlackMatrix);
  71. if (bits == null)
  72. return null;
  73. decoderResult = decoder.decode(bits, hints);
  74. points = NO_POINTS;
  75. }
  76. else
  77. {
  78. var detectorResult = new Detector(image.BlackMatrix).detect(hints);
  79. if (detectorResult == null)
  80. return null;
  81. decoderResult = decoder.decode(detectorResult.Bits, hints);
  82. points = detectorResult.Points;
  83. }
  84. if (decoderResult == null)
  85. return null;
  86. // If the code was mirrored: swap the bottom-left and the top-right points.
  87. var data = decoderResult.Other as QRCodeDecoderMetaData;
  88. if (data != null)
  89. {
  90. data.applyMirroredCorrection(points);
  91. }
  92. var result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.QR_CODE);
  93. var byteSegments = decoderResult.ByteSegments;
  94. if (byteSegments != null)
  95. {
  96. result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments);
  97. }
  98. var ecLevel = decoderResult.ECLevel;
  99. if (ecLevel != null)
  100. {
  101. result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel);
  102. }
  103. if (decoderResult.StructuredAppend)
  104. {
  105. result.putMetadata(ResultMetadataType.STRUCTURED_APPEND_SEQUENCE, decoderResult.StructuredAppendSequenceNumber);
  106. result.putMetadata(ResultMetadataType.STRUCTURED_APPEND_PARITY, decoderResult.StructuredAppendParity);
  107. }
  108. return result;
  109. }
  110. /// <summary>
  111. /// Resets any internal state the implementation has after a decode, to prepare it
  112. /// for reuse.
  113. /// </summary>
  114. public void reset()
  115. {
  116. // do nothing
  117. }
  118. /// <summary>
  119. /// This method detects a code in a "pure" image -- that is, pure monochrome image
  120. /// which contains only an unrotated, unskewed, image of a code, with some white border
  121. /// around it. This is a specialized method that works exceptionally fast in this special
  122. /// case.
  123. ///
  124. /// <seealso cref="ZXing.Datamatrix.DataMatrixReader.extractPureBits(BitMatrix)" />
  125. /// </summary>
  126. private static BitMatrix extractPureBits(BitMatrix image)
  127. {
  128. int[] leftTopBlack = image.getTopLeftOnBit();
  129. int[] rightBottomBlack = image.getBottomRightOnBit();
  130. if (leftTopBlack == null || rightBottomBlack == null)
  131. {
  132. return null;
  133. }
  134. float moduleSize;
  135. if (!QRCodeReader.moduleSize(leftTopBlack, image, out moduleSize))
  136. return null;
  137. int top = leftTopBlack[1];
  138. int bottom = rightBottomBlack[1];
  139. int left = leftTopBlack[0];
  140. int right = rightBottomBlack[0];
  141. // Sanity check!
  142. if (left >= right || top >= bottom)
  143. {
  144. return null;
  145. }
  146. if (bottom - top != right - left)
  147. {
  148. // Special case, where bottom-right module wasn't black so we found something else in the last row
  149. // Assume it's a square, so use height as the width
  150. right = left + (bottom - top);
  151. }
  152. int matrixWidth = (int)Math.Round((right - left + 1) / moduleSize);
  153. int matrixHeight = (int)Math.Round((bottom - top + 1) / moduleSize);
  154. if (matrixWidth <= 0 || matrixHeight <= 0)
  155. {
  156. return null;
  157. }
  158. if (matrixHeight != matrixWidth)
  159. {
  160. // Only possibly decode square regions
  161. return null;
  162. }
  163. // Push in the "border" by half the module width so that we start
  164. // sampling in the middle of the module. Just in case the image is a
  165. // little off, this will help recover.
  166. int nudge = (int)(moduleSize / 2.0f);
  167. top += nudge;
  168. left += nudge;
  169. // But careful that this does not sample off the edge
  170. int nudgedTooFarRight = left + (int)((matrixWidth - 1) * moduleSize) - (right - 1);
  171. if (nudgedTooFarRight > 0)
  172. {
  173. if (nudgedTooFarRight > nudge)
  174. {
  175. // Neither way fits; abort
  176. return null;
  177. }
  178. left -= nudgedTooFarRight;
  179. }
  180. int nudgedTooFarDown = top + (int)((matrixHeight - 1) * moduleSize) - (bottom - 1);
  181. if (nudgedTooFarDown > 0)
  182. {
  183. if (nudgedTooFarDown > nudge)
  184. {
  185. // Neither way fits; abort
  186. return null;
  187. }
  188. top -= nudgedTooFarDown;
  189. }
  190. // Now just read off the bits
  191. BitMatrix bits = new BitMatrix(matrixWidth, matrixHeight);
  192. for (int y = 0; y < matrixHeight; y++)
  193. {
  194. int iOffset = top + (int)(y * moduleSize);
  195. for (int x = 0; x < matrixWidth; x++)
  196. {
  197. if (image[left + (int)(x * moduleSize), iOffset])
  198. {
  199. bits[x, y] = true;
  200. }
  201. }
  202. }
  203. return bits;
  204. }
  205. private static bool moduleSize(int[] leftTopBlack, BitMatrix image, out float msize)
  206. {
  207. int height = image.Height;
  208. int width = image.Width;
  209. int x = leftTopBlack[0];
  210. int y = leftTopBlack[1];
  211. bool inBlack = true;
  212. int transitions = 0;
  213. while (x < width && y < height)
  214. {
  215. if (inBlack != image[x, y])
  216. {
  217. if (++transitions == 5)
  218. {
  219. break;
  220. }
  221. inBlack = !inBlack;
  222. }
  223. x++;
  224. y++;
  225. }
  226. if (x == width || y == height)
  227. {
  228. msize = 0.0f;
  229. return false;
  230. }
  231. msize = (x - leftTopBlack[0]) / 7.0f;
  232. return true;
  233. }
  234. }
  235. }