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.

BitMatrix.cs 7.9 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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. namespace ZXing.Common
  18. {
  19. /// <summary>
  20. /// <p>Represents a 2D matrix of bits. In function arguments below, and throughout the common
  21. /// module, x is the column position, and y is the row position. The ordering is always x, y.
  22. /// The origin is at the top-left.</p>
  23. /// <p>Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins
  24. /// with a new int. This is done intentionally so that we can copy out a row into a BitArray very
  25. /// efficiently.</p>
  26. /// <p>The ordering of bits is row-major. Within each int, the least significant bits are used first,
  27. /// meaning they represent lower x values. This is compatible with BitArray's implementation.</p>
  28. /// </summary>
  29. /// <author>Sean Owen</author>
  30. /// <author>dswitkin@google.com (Daniel Switkin)</author>
  31. public sealed partial class BitMatrix
  32. {
  33. private readonly int width;
  34. private readonly int height;
  35. private readonly int rowSize;
  36. private readonly int[] bits;
  37. /// <returns> The width of the matrix
  38. /// </returns>
  39. public int Width
  40. {
  41. get
  42. {
  43. return width;
  44. }
  45. }
  46. /// <returns> The height of the matrix
  47. /// </returns>
  48. public int Height
  49. {
  50. get
  51. {
  52. return height;
  53. }
  54. }
  55. // A helper to construct a square matrix.
  56. public BitMatrix(int dimension)
  57. : this(dimension, dimension)
  58. {
  59. }
  60. public BitMatrix(int width, int height)
  61. {
  62. if (width < 1 || height < 1)
  63. {
  64. throw new System.ArgumentException("Both dimensions must be greater than 0");
  65. }
  66. this.width = width;
  67. this.height = height;
  68. this.rowSize = (width + 31) >> 5;
  69. bits = new int[rowSize * height];
  70. }
  71. private BitMatrix(int width, int height, int rowSize, int[] bits)
  72. {
  73. this.width = width;
  74. this.height = height;
  75. this.rowSize = rowSize;
  76. this.bits = bits;
  77. }
  78. /// <summary> <p>Gets the requested bit, where true means black.</p>
  79. ///
  80. /// </summary>
  81. /// <param name="x">The horizontal component (i.e. which column)
  82. /// </param>
  83. /// <param name="y">The vertical component (i.e. which row)
  84. /// </param>
  85. /// <returns> value of given bit in matrix
  86. /// </returns>
  87. public bool this[int x, int y]
  88. {
  89. get
  90. {
  91. int offset = y * rowSize + (x >> 5);
  92. return (((int)((uint)(bits[offset]) >> (x & 0x1f))) & 1) != 0;
  93. }
  94. set
  95. {
  96. if (value)
  97. {
  98. int offset = y * rowSize + (x >> 5);
  99. bits[offset] |= 1 << (x & 0x1f);
  100. }
  101. }
  102. }
  103. /// <summary> <p>Flips the given bit.</p>
  104. ///
  105. /// </summary>
  106. /// <param name="x">The horizontal component (i.e. which column)
  107. /// </param>
  108. /// <param name="y">The vertical component (i.e. which row)
  109. /// </param>
  110. public void flip(int x, int y)
  111. {
  112. int offset = y * rowSize + (x >> 5);
  113. bits[offset] ^= 1 << (x & 0x1f);
  114. }
  115. /// <summary> <p>Sets a square region of the bit matrix to true.</p>
  116. ///
  117. /// </summary>
  118. /// <param name="left">The horizontal position to begin at (inclusive)
  119. /// </param>
  120. /// <param name="top">The vertical position to begin at (inclusive)
  121. /// </param>
  122. /// <param name="width">The width of the region
  123. /// </param>
  124. /// <param name="height">The height of the region
  125. /// </param>
  126. public void setRegion(int left, int top, int width, int height)
  127. {
  128. if (top < 0 || left < 0)
  129. {
  130. throw new System.ArgumentException("Left and top must be nonnegative");
  131. }
  132. if (height < 1 || width < 1)
  133. {
  134. throw new System.ArgumentException("Height and width must be at least 1");
  135. }
  136. int right = left + width;
  137. int bottom = top + height;
  138. if (bottom > this.height || right > this.width)
  139. {
  140. throw new System.ArgumentException("The region must fit inside the matrix");
  141. }
  142. for (int y = top; y < bottom; y++)
  143. {
  144. int offset = y * rowSize;
  145. for (int x = left; x < right; x++)
  146. {
  147. bits[offset + (x >> 5)] |= 1 << (x & 0x1f);
  148. }
  149. }
  150. }
  151. /// <summary> A fast method to retrieve one row of data from the matrix as a BitArray.
  152. ///
  153. /// </summary>
  154. /// <param name="y">The row to retrieve
  155. /// </param>
  156. /// <param name="row">An optional caller-allocated BitArray, will be allocated if null or too small
  157. /// </param>
  158. /// <returns> The resulting BitArray - this reference should always be used even when passing
  159. /// your own row
  160. /// </returns>
  161. public BitArray getRow(int y, BitArray row)
  162. {
  163. if (row == null || row.Size < width)
  164. {
  165. row = new BitArray(width);
  166. }
  167. else
  168. {
  169. row.clear();
  170. }
  171. int offset = y * rowSize;
  172. for (int x = 0; x < rowSize; x++)
  173. {
  174. row.setBulk(x << 5, bits[offset + x]);
  175. }
  176. return row;
  177. }
  178. /// <summary>
  179. /// Sets the row.
  180. /// </summary>
  181. /// <param name="y">row to set</param>
  182. /// <param name="row">{@link BitArray} to copy from</param>
  183. public void setRow(int y, BitArray row)
  184. {
  185. Array.Copy(row.Array, 0, bits, y * rowSize, rowSize);
  186. }
  187. /// <summary>
  188. /// This is useful in detecting a corner of a 'pure' barcode.
  189. /// </summary>
  190. /// <returns>{x,y} coordinate of top-left-most 1 bit, or null if it is all white</returns>
  191. public int[] getTopLeftOnBit()
  192. {
  193. int bitsOffset = 0;
  194. while (bitsOffset < bits.Length && bits[bitsOffset] == 0)
  195. {
  196. bitsOffset++;
  197. }
  198. if (bitsOffset == bits.Length)
  199. {
  200. return null;
  201. }
  202. int y = bitsOffset / rowSize;
  203. int x = (bitsOffset % rowSize) << 5;
  204. int theBits = bits[bitsOffset];
  205. int bit = 0;
  206. while ((theBits << (31 - bit)) == 0)
  207. {
  208. bit++;
  209. }
  210. x += bit;
  211. return new[] { x, y };
  212. }
  213. public int[] getBottomRightOnBit()
  214. {
  215. int bitsOffset = bits.Length - 1;
  216. while (bitsOffset >= 0 && bits[bitsOffset] == 0)
  217. {
  218. bitsOffset--;
  219. }
  220. if (bitsOffset < 0)
  221. {
  222. return null;
  223. }
  224. int y = bitsOffset / rowSize;
  225. int x = (bitsOffset % rowSize) << 5;
  226. int theBits = bits[bitsOffset];
  227. int bit = 31;
  228. while (((int)((uint)theBits >> bit)) == 0) // (theBits >>> bit)
  229. {
  230. bit--;
  231. }
  232. x += bit;
  233. return new int[] { x, y };
  234. }
  235. }
  236. }