MaskUtil.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * Copyright 2008 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 FastReport.Barcode.QRCode
  18. {
  19. /*/// <author> satorux@google.com (Satoru Takabayashi) - creator
  20. /// </author>
  21. /// <author> dswitkin@google.com (Daniel Switkin) - ported from C++
  22. /// </author>
  23. /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
  24. /// </author>*/
  25. internal sealed class MaskUtil
  26. {
  27. private MaskUtil()
  28. {
  29. // do nothing
  30. }
  31. // Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and
  32. // give penalty to them. Example: 00000 or 11111.
  33. public static int applyMaskPenaltyRule1(ByteMatrix matrix)
  34. {
  35. return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false);
  36. }
  37. // Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give
  38. // penalty to them.
  39. public static int applyMaskPenaltyRule2(ByteMatrix matrix)
  40. {
  41. int penalty = 0;
  42. sbyte[][] array = matrix.Array;
  43. int width = matrix.Width;
  44. int height = matrix.Height;
  45. for (int y = 0; y < height - 1; ++y)
  46. {
  47. for (int x = 0; x < width - 1; ++x)
  48. {
  49. int value_Renamed = array[y][x];
  50. if (value_Renamed == array[y][x + 1] && value_Renamed == array[y + 1][x] && value_Renamed == array[y + 1][x + 1])
  51. {
  52. penalty += 3;
  53. }
  54. }
  55. }
  56. return penalty;
  57. }
  58. // Apply mask penalty rule 3 and return the penalty. Find consecutive cells of 00001011101 or
  59. // 10111010000, and give penalty to them. If we find patterns like 000010111010000, we give
  60. // penalties twice (i.e. 40 * 2).
  61. public static int applyMaskPenaltyRule3(ByteMatrix matrix)
  62. {
  63. int penalty = 0;
  64. sbyte[][] array = matrix.Array;
  65. int width = matrix.Width;
  66. int height = matrix.Height;
  67. for (int y = 0; y < height; ++y)
  68. {
  69. for (int x = 0; x < width; ++x)
  70. {
  71. // Tried to simplify following conditions but failed.
  72. if (x + 6 < width && array[y][x] == 1 && array[y][x + 1] == 0 && array[y][x + 2] == 1 && array[y][x + 3] == 1 && array[y][x + 4] == 1 && array[y][x + 5] == 0 && array[y][x + 6] == 1 && ((x + 10 < width && array[y][x + 7] == 0 && array[y][x + 8] == 0 && array[y][x + 9] == 0 && array[y][x + 10] == 0) || (x - 4 >= 0 && array[y][x - 1] == 0 && array[y][x - 2] == 0 && array[y][x - 3] == 0 && array[y][x - 4] == 0)))
  73. {
  74. penalty += 40;
  75. }
  76. if (y + 6 < height && array[y][x] == 1 && array[y + 1][x] == 0 && array[y + 2][x] == 1 && array[y + 3][x] == 1 && array[y + 4][x] == 1 && array[y + 5][x] == 0 && array[y + 6][x] == 1 && ((y + 10 < height && array[y + 7][x] == 0 && array[y + 8][x] == 0 && array[y + 9][x] == 0 && array[y + 10][x] == 0) || (y - 4 >= 0 && array[y - 1][x] == 0 && array[y - 2][x] == 0 && array[y - 3][x] == 0 && array[y - 4][x] == 0)))
  77. {
  78. penalty += 40;
  79. }
  80. }
  81. }
  82. return penalty;
  83. }
  84. // Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give
  85. // penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. Examples:
  86. // - 0% => 100
  87. // - 40% => 20
  88. // - 45% => 10
  89. // - 50% => 0
  90. // - 55% => 10
  91. // - 55% => 20
  92. // - 100% => 100
  93. public static int applyMaskPenaltyRule4(ByteMatrix matrix)
  94. {
  95. int numDarkCells = 0;
  96. sbyte[][] array = matrix.Array;
  97. int width = matrix.Width;
  98. int height = matrix.Height;
  99. for (int y = 0; y < height; ++y)
  100. {
  101. for (int x = 0; x < width; ++x)
  102. {
  103. if (array[y][x] == 1)
  104. {
  105. numDarkCells += 1;
  106. }
  107. }
  108. }
  109. int numTotalCells = matrix.Height * matrix.Width;
  110. double darkRatio = (double) numDarkCells / numTotalCells;
  111. //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
  112. return System.Math.Abs((int) (darkRatio * 100 - 50)) / 5 * 10;
  113. }
  114. // Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask
  115. // pattern conditions.
  116. public static bool getDataMaskBit(int maskPattern, int x, int y)
  117. {
  118. if (!QRCode.isValidMaskPattern(maskPattern))
  119. {
  120. throw new System.ArgumentException("Invalid mask pattern");
  121. }
  122. int intermediate, temp;
  123. switch (maskPattern)
  124. {
  125. case 0:
  126. intermediate = (y + x) & 0x1;
  127. break;
  128. case 1:
  129. intermediate = y & 0x1;
  130. break;
  131. case 2:
  132. intermediate = x % 3;
  133. break;
  134. case 3:
  135. intermediate = (y + x) % 3;
  136. break;
  137. case 4:
  138. intermediate = ((SupportClass.URShift(y, 1)) + (x / 3)) & 0x1;
  139. break;
  140. case 5:
  141. temp = y * x;
  142. intermediate = (temp & 0x1) + (temp % 3);
  143. break;
  144. case 6:
  145. temp = y * x;
  146. intermediate = (((temp & 0x1) + (temp % 3)) & 0x1);
  147. break;
  148. case 7:
  149. temp = y * x;
  150. intermediate = (((temp % 3) + ((y + x) & 0x1)) & 0x1);
  151. break;
  152. default:
  153. throw new System.ArgumentException("Invalid mask pattern: " + maskPattern);
  154. }
  155. return intermediate == 0;
  156. }
  157. // Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both
  158. // vertical and horizontal orders respectively.
  159. private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, bool isHorizontal)
  160. {
  161. int penalty = 0;
  162. int numSameBitCells = 0;
  163. int prevBit = - 1;
  164. // Horizontal mode:
  165. // for (int i = 0; i < matrix.height(); ++i) {
  166. // for (int j = 0; j < matrix.width(); ++j) {
  167. // int bit = matrix.get(i, j);
  168. // Vertical mode:
  169. // for (int i = 0; i < matrix.width(); ++i) {
  170. // for (int j = 0; j < matrix.height(); ++j) {
  171. // int bit = matrix.get(j, i);
  172. int iLimit = isHorizontal?matrix.Height:matrix.Width;
  173. int jLimit = isHorizontal?matrix.Width:matrix.Height;
  174. sbyte[][] array = matrix.Array;
  175. for (int i = 0; i < iLimit; ++i)
  176. {
  177. for (int j = 0; j < jLimit; ++j)
  178. {
  179. int bit = isHorizontal?array[i][j]:array[j][i];
  180. if (bit == prevBit)
  181. {
  182. numSameBitCells += 1;
  183. // Found five repetitive cells with the same color (bit).
  184. // We'll give penalty of 3.
  185. if (numSameBitCells == 5)
  186. {
  187. penalty += 3;
  188. }
  189. else if (numSameBitCells > 5)
  190. {
  191. // After five repetitive cells, we'll add the penalty one
  192. // by one.
  193. penalty += 1;
  194. }
  195. }
  196. else
  197. {
  198. numSameBitCells = 1; // Include the cell itself.
  199. prevBit = bit;
  200. }
  201. }
  202. numSameBitCells = 0; // Clear at each row/column.
  203. }
  204. return penalty;
  205. }
  206. }
  207. }