not really known
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.

278 lines
7.1 KiB

  1. /*
  2. Ported to JavaScript by Lazar Laszlo 2011
  3. lazarsoft@gmail.com, www.lazarsoft.info
  4. */
  5. /*
  6. *
  7. * Copyright 2007 ZXing authors
  8. *
  9. * Licensed under the Apache License, Version 2.0 (the "License");
  10. * you may not use this file except in compliance with the License.
  11. * You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing, software
  16. * distributed under the License is distributed on an "AS IS" BASIS,
  17. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. * See the License for the specific language governing permissions and
  19. * limitations under the License.
  20. */
  21. function AlignmentPattern(posX, posY, estimatedModuleSize)
  22. {
  23. this.x=posX;
  24. this.y=posY;
  25. this.count = 1;
  26. this.estimatedModuleSize = estimatedModuleSize;
  27. this.__defineGetter__("EstimatedModuleSize", function()
  28. {
  29. return this.estimatedModuleSize;
  30. });
  31. this.__defineGetter__("Count", function()
  32. {
  33. return this.count;
  34. });
  35. this.__defineGetter__("X", function()
  36. {
  37. return Math.floor(this.x);
  38. });
  39. this.__defineGetter__("Y", function()
  40. {
  41. return Math.floor(this.y);
  42. });
  43. this.incrementCount = function()
  44. {
  45. this.count++;
  46. }
  47. this.aboutEquals=function( moduleSize, i, j)
  48. {
  49. if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize)
  50. {
  51. var moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize);
  52. return moduleSizeDiff <= 1.0 || moduleSizeDiff / this.estimatedModuleSize <= 1.0;
  53. }
  54. return false;
  55. }
  56. }
  57. function AlignmentPatternFinder( image, startX, startY, width, height, moduleSize, resultPointCallback)
  58. {
  59. this.image = image;
  60. this.possibleCenters = new Array();
  61. this.startX = startX;
  62. this.startY = startY;
  63. this.width = width;
  64. this.height = height;
  65. this.moduleSize = moduleSize;
  66. this.crossCheckStateCount = new Array(0,0,0);
  67. this.resultPointCallback = resultPointCallback;
  68. this.centerFromEnd=function(stateCount, end)
  69. {
  70. return (end - stateCount[2]) - stateCount[1] / 2.0;
  71. }
  72. this.foundPatternCross = function(stateCount)
  73. {
  74. var moduleSize = this.moduleSize;
  75. var maxVariance = moduleSize / 2.0;
  76. for (var i = 0; i < 3; i++)
  77. {
  78. if (Math.abs(moduleSize - stateCount[i]) >= maxVariance)
  79. {
  80. return false;
  81. }
  82. }
  83. return true;
  84. }
  85. this.crossCheckVertical=function( startI, centerJ, maxCount, originalStateCountTotal)
  86. {
  87. var image = this.image;
  88. var maxI = qrcode.height;
  89. var stateCount = this.crossCheckStateCount;
  90. stateCount[0] = 0;
  91. stateCount[1] = 0;
  92. stateCount[2] = 0;
  93. // Start counting up from center
  94. var i = startI;
  95. while (i >= 0 && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount)
  96. {
  97. stateCount[1]++;
  98. i--;
  99. }
  100. // If already too many modules in this state or ran off the edge:
  101. if (i < 0 || stateCount[1] > maxCount)
  102. {
  103. return NaN;
  104. }
  105. while (i >= 0 && !image[centerJ + i*qrcode.width] && stateCount[0] <= maxCount)
  106. {
  107. stateCount[0]++;
  108. i--;
  109. }
  110. if (stateCount[0] > maxCount)
  111. {
  112. return NaN;
  113. }
  114. // Now also count down from center
  115. i = startI + 1;
  116. while (i < maxI && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount)
  117. {
  118. stateCount[1]++;
  119. i++;
  120. }
  121. if (i == maxI || stateCount[1] > maxCount)
  122. {
  123. return NaN;
  124. }
  125. while (i < maxI && !image[centerJ + i*qrcode.width] && stateCount[2] <= maxCount)
  126. {
  127. stateCount[2]++;
  128. i++;
  129. }
  130. if (stateCount[2] > maxCount)
  131. {
  132. return NaN;
  133. }
  134. var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
  135. if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal)
  136. {
  137. return NaN;
  138. }
  139. return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, i):NaN;
  140. }
  141. this.handlePossibleCenter=function( stateCount, i, j)
  142. {
  143. var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
  144. var centerJ = this.centerFromEnd(stateCount, j);
  145. var centerI = this.crossCheckVertical(i, Math.floor (centerJ), 2 * stateCount[1], stateCountTotal);
  146. if (!isNaN(centerI))
  147. {
  148. var estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0;
  149. var max = this.possibleCenters.length;
  150. for (var index = 0; index < max; index++)
  151. {
  152. var center = this.possibleCenters[index];
  153. // Look for about the same center and module size:
  154. if (center.aboutEquals(estimatedModuleSize, centerI, centerJ))
  155. {
  156. return new AlignmentPattern(centerJ, centerI, estimatedModuleSize);
  157. }
  158. }
  159. // Hadn't found this before; save it
  160. var point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize);
  161. this.possibleCenters.push(point);
  162. if (this.resultPointCallback != null)
  163. {
  164. this.resultPointCallback.foundPossibleResultPoint(point);
  165. }
  166. }
  167. return null;
  168. }
  169. this.find = function()
  170. {
  171. var startX = this.startX;
  172. var height = this.height;
  173. var maxJ = startX + width;
  174. var middleI = startY + (height >> 1);
  175. // We are looking for black/white/black modules in 1:1:1 ratio;
  176. // this tracks the number of black/white/black modules seen so far
  177. var stateCount = new Array(0,0,0);
  178. for (var iGen = 0; iGen < height; iGen++)
  179. {
  180. // Search from middle outwards
  181. var i = middleI + ((iGen & 0x01) == 0?((iGen + 1) >> 1):- ((iGen + 1) >> 1));
  182. stateCount[0] = 0;
  183. stateCount[1] = 0;
  184. stateCount[2] = 0;
  185. var j = startX;
  186. // Burn off leading white pixels before anything else; if we start in the middle of
  187. // a white run, it doesn't make sense to count its length, since we don't know if the
  188. // white run continued to the left of the start point
  189. while (j < maxJ && !image[j + qrcode.width* i])
  190. {
  191. j++;
  192. }
  193. var currentState = 0;
  194. while (j < maxJ)
  195. {
  196. if (image[j + i*qrcode.width])
  197. {
  198. // Black pixel
  199. if (currentState == 1)
  200. {
  201. // Counting black pixels
  202. stateCount[currentState]++;
  203. }
  204. else
  205. {
  206. // Counting white pixels
  207. if (currentState == 2)
  208. {
  209. // A winner?
  210. if (this.foundPatternCross(stateCount))
  211. {
  212. // Yes
  213. var confirmed = this.handlePossibleCenter(stateCount, i, j);
  214. if (confirmed != null)
  215. {
  216. return confirmed;
  217. }
  218. }
  219. stateCount[0] = stateCount[2];
  220. stateCount[1] = 1;
  221. stateCount[2] = 0;
  222. currentState = 1;
  223. }
  224. else
  225. {
  226. stateCount[++currentState]++;
  227. }
  228. }
  229. }
  230. else
  231. {
  232. // White pixel
  233. if (currentState == 1)
  234. {
  235. // Counting black pixels
  236. currentState++;
  237. }
  238. stateCount[currentState]++;
  239. }
  240. j++;
  241. }
  242. if (this.foundPatternCross(stateCount))
  243. {
  244. var confirmed = this.handlePossibleCenter(stateCount, i, maxJ);
  245. if (confirmed != null)
  246. {
  247. return confirmed;
  248. }
  249. }
  250. }
  251. // Hmm, nothing we saw was observed and confirmed twice. If we had
  252. // any guess at all, return it.
  253. if (!(this.possibleCenters.length == 0))
  254. {
  255. return this.possibleCenters[0];
  256. }
  257. throw "Couldn't find enough alignment patterns";
  258. }
  259. }