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