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+ }
0 commit comments