1+ using Avalonia ;
2+ using Avalonia . Media ;
3+ using Gma . QrCodeNet . Encoding ;
4+
5+ namespace Ursa . Controls ;
6+
7+ public partial class QRCode
8+ {
9+ /// <summary>
10+ /// Processes a symbol if set and adds the required geometry.
11+ /// </summary>
12+ /// <param name="geometry">Geometry containing the QRCode Geometry</param>
13+ /// <param name="bitMatrix">BitMatrix containing the data</param>
14+ /// <param name="row">The row of the symbol being processed</param>
15+ /// <param name="column">The column of the symbol being processed</param>
16+ /// <param name="symbolBounds">The bounds of the symbol being processed</param>
17+ /// <param name="cornerRatio"></param>
18+ /// <returns>True if the symbol was processed, otherwise false</returns>
19+ private static void ProcessSymbolIfSet (
20+ PathGeometry geometry ,
21+ BitMatrix bitMatrix ,
22+ int row ,
23+ int column ,
24+ Rect symbolBounds ,
25+ double cornerRatio )
26+ {
27+ if ( cornerRatio == 0 )
28+ {
29+ var simpleFigure = new PathFigure ( ) { StartPoint = symbolBounds . TopLeft , } ;
30+ simpleFigure . Segments ! . Add ( new LineSegment { Point = symbolBounds . TopRight } ) ;
31+ simpleFigure . Segments . Add ( new LineSegment { Point = symbolBounds . BottomRight } ) ;
32+ simpleFigure . Segments . Add ( new LineSegment { Point = symbolBounds . BottomLeft } ) ;
33+ geometry . Figures ? . Add ( simpleFigure ) ;
34+ return ;
35+ }
36+ var cornerRadius = symbolBounds . Size * cornerRatio ;
37+ var cornerFlags = GetSetSymbolCornerFlags ( bitMatrix , row , column ) ;
38+ var figure = new PathFigure
39+ { StartPoint = new Point ( symbolBounds . Left , symbolBounds . Top + cornerRadius . Height ) } ;
40+
41+ // Top Left
42+ if ( ( cornerFlags & CornerFlags . TopLeft ) != 0 )
43+ {
44+ figure . Segments ! . Add ( new LineSegment { Point = symbolBounds . TopLeft } ) ;
45+ figure . Segments ! . Add ( new LineSegment
46+ { Point = new Point ( symbolBounds . Right - cornerRadius . Width , symbolBounds . Top ) } ) ;
47+ }
48+ else
49+ {
50+ figure . Segments ! . Add ( new ArcSegment
51+ {
52+ SweepDirection = SweepDirection . Clockwise ,
53+ Point = new Point ( symbolBounds . Left + cornerRadius . Width , symbolBounds . Top ) ,
54+ Size = cornerRadius
55+ } ) ;
56+ figure . Segments . Add ( new LineSegment ( )
57+ {
58+ Point = new Point ( symbolBounds . Right - cornerRadius . Width , symbolBounds . Top ) ,
59+ } ) ;
60+ }
61+
62+ // Top Right
63+ if ( ( cornerFlags & CornerFlags . TopRight ) != 0 )
64+ {
65+ figure . Segments ! . Add ( new LineSegment { Point = symbolBounds . TopRight } ) ;
66+ figure . Segments . Add ( new LineSegment ( )
67+ {
68+ Point = new Point ( symbolBounds . Right , symbolBounds . Bottom - cornerRadius . Height ) ,
69+ } ) ;
70+ }
71+ else
72+ {
73+ figure . Segments ! . Add ( new ArcSegment
74+ {
75+ SweepDirection = SweepDirection . Clockwise ,
76+ Point = new Point ( symbolBounds . Right , symbolBounds . Top + cornerRadius . Height ) ,
77+ Size = cornerRadius
78+ } ) ;
79+ figure . Segments . Add ( new LineSegment ( )
80+ {
81+ Point = new Point ( symbolBounds . Right , symbolBounds . Bottom - cornerRadius . Height ) ,
82+ } ) ;
83+ }
84+
85+ // Bottom Right
86+ if ( ( cornerFlags & CornerFlags . BottomRight ) != 0 )
87+ {
88+ figure . Segments ! . Add ( new LineSegment { Point = symbolBounds . BottomRight } ) ;
89+ figure . Segments ! . Add ( new LineSegment
90+ { Point = new Point ( symbolBounds . Left + cornerRadius . Width , symbolBounds . Bottom ) } ) ;
91+ }
92+ else
93+ {
94+ figure . Segments ! . Add ( new ArcSegment
95+ {
96+ SweepDirection = SweepDirection . Clockwise ,
97+ Point = new Point ( symbolBounds . Right - cornerRadius . Width , symbolBounds . Bottom ) ,
98+ Size = cornerRadius
99+ } ) ;
100+ figure . Segments ! . Add ( new LineSegment
101+ { Point = new Point ( symbolBounds . Left + cornerRadius . Width , symbolBounds . Bottom ) } ) ;
102+ }
103+
104+ // Bottom Left
105+ if ( ( cornerFlags & CornerFlags . BottomLeft ) != 0 )
106+ {
107+ figure . Segments ! . Add ( new LineSegment { Point = symbolBounds . BottomLeft } ) ;
108+ figure . Segments ! . Add ( new LineSegment { Point = figure . StartPoint } ) ;
109+ }
110+ else
111+ {
112+ figure . Segments ! . Add ( new ArcSegment
113+ {
114+ SweepDirection = SweepDirection . Clockwise ,
115+ Point = new Point ( symbolBounds . Left , symbolBounds . Bottom - cornerRadius . Height ) ,
116+ Size = cornerRadius
117+ } ) ;
118+ figure . Segments ! . Add ( new LineSegment { Point = figure . StartPoint } ) ;
119+ }
120+
121+ geometry . Figures ? . Add ( figure ) ;
122+ }
123+
124+ /// <summary>
125+ /// Gets the corner flags indicating how a set symbol is to be processed
126+ /// </summary>
127+ /// <param name="bitMatrix">BitMatrix containing the data</param>
128+ /// <param name="row">The row of the symbol being processed</param>
129+ /// <param name="column">The column of the symbol being processed</param>
130+ /// <returns>The corner flags for a set symbol</returns>
131+ private static CornerFlags GetSetSymbolCornerFlags ( BitMatrix bitMatrix , int row , int column )
132+ {
133+ var flags = CornerFlags . None ;
134+
135+ if ( ! IsValid ( bitMatrix , column , row ) )
136+ return flags ;
137+
138+ if ( IsValid ( bitMatrix , column , row - 1 ) || IsValid ( bitMatrix , column - 1 , row ) )
139+ flags |= CornerFlags . TopLeft ;
140+ if ( IsValid ( bitMatrix , column , row - 1 ) || IsValid ( bitMatrix , column + 1 , row ) )
141+ flags |= CornerFlags . TopRight ;
142+ if ( IsValid ( bitMatrix , column , row + 1 ) || IsValid ( bitMatrix , column + 1 , row ) )
143+ flags |= CornerFlags . BottomRight ;
144+ if ( IsValid ( bitMatrix , column , row + 1 ) || IsValid ( bitMatrix , column - 1 , row ) )
145+ flags |= CornerFlags . BottomLeft ;
146+
147+ return flags ;
148+ }
149+
150+ /// <summary>
151+ /// Processes a symbol if unset and adds the required geometry.
152+ /// </summary>
153+ /// <param name="geometry">Geometry containing the QRCode Geometry</param>
154+ /// <param name="bitMatrix">BitMatrix containing the data</param>
155+ /// <param name="row">The row of the symbol being processed</param>
156+ /// <param name="column">The column of the symbol being processed</param>
157+ /// <param name="symbolBounds">The bounds of the symbol being processed</param>
158+ /// <param name="cornerRatio"></param>
159+ private static void ProcessSymbolIfUnset ( PathGeometry geometry , BitMatrix bitMatrix , int row , int column ,
160+ Rect symbolBounds , double cornerRatio )
161+ {
162+ // If filled, no action required
163+ if ( IsValid ( bitMatrix , column , row ) )
164+ return ;
165+ if ( cornerRatio == 0 ) return ;
166+
167+ var cornerFlags = GetUnsetSymbolCornerFlags ( bitMatrix , row , column ) ;
168+
169+ // If there are no nearby bits set, there's no need to smooth corners
170+ if ( cornerFlags == CornerFlags . None )
171+ return ;
172+
173+ var cornerRadius = symbolBounds . Size * cornerRatio ;
174+
175+ // Top Left
176+ if ( ( cornerFlags & CornerFlags . TopLeft ) != 0 )
177+ {
178+ var start = new Point ( symbolBounds . Left , symbolBounds . Top + cornerRadius . Height ) ;
179+
180+ geometry . Figures ! . Add ( new PathFigure
181+ {
182+ StartPoint = start ,
183+ Segments =
184+ [
185+ new LineSegment { Point = symbolBounds . TopLeft } ,
186+ new LineSegment { Point = new Point ( symbolBounds . Left + cornerRadius . Width , symbolBounds . Top ) } ,
187+ new ArcSegment
188+ {
189+ SweepDirection = SweepDirection . CounterClockwise ,
190+ Point = start ,
191+ Size = cornerRadius
192+ }
193+ ]
194+ } ) ;
195+ }
196+
197+ // Top Right
198+ if ( ( cornerFlags & CornerFlags . TopRight ) != 0 )
199+ {
200+ var start = new Point ( symbolBounds . Right - cornerRadius . Width , symbolBounds . Top ) ;
201+
202+ geometry . Figures ! . Add ( new PathFigure
203+ {
204+ StartPoint = start ,
205+ Segments =
206+ [
207+ new LineSegment { Point = symbolBounds . TopRight } ,
208+ new LineSegment { Point = new Point ( symbolBounds . Right , symbolBounds . Top + cornerRadius . Height ) } ,
209+ new ArcSegment
210+ {
211+ SweepDirection = SweepDirection . CounterClockwise ,
212+ Point = start ,
213+ Size = cornerRadius
214+ }
215+ ]
216+ } ) ;
217+ }
218+
219+ // Bottom Right
220+ if ( ( cornerFlags & CornerFlags . BottomRight ) != 0 )
221+ {
222+ var start = new Point ( symbolBounds . Right , symbolBounds . Bottom - cornerRadius . Height ) ;
223+
224+ geometry . Figures ! . Add ( new PathFigure
225+ {
226+ StartPoint = start ,
227+ Segments =
228+ [
229+ new LineSegment { Point = symbolBounds . BottomRight } ,
230+ new LineSegment { Point = new Point ( symbolBounds . Right - cornerRadius . Width , symbolBounds . Bottom ) } ,
231+ new ArcSegment
232+ {
233+ SweepDirection = SweepDirection . CounterClockwise ,
234+ Point = start ,
235+ Size = cornerRadius
236+ }
237+ ]
238+ } ) ;
239+ }
240+
241+ // Bottom Left
242+ if ( ( cornerFlags & CornerFlags . BottomLeft ) != 0 )
243+ {
244+ var start = new Point ( symbolBounds . Left + cornerRadius . Width , symbolBounds . Bottom ) ;
245+
246+ geometry . Figures ! . Add ( new PathFigure
247+ {
248+ StartPoint = start ,
249+ Segments =
250+ [
251+ new LineSegment { Point = symbolBounds . BottomLeft } ,
252+ new LineSegment { Point = new Point ( symbolBounds . Left , symbolBounds . Bottom - cornerRadius . Height ) } ,
253+ new ArcSegment
254+ {
255+ SweepDirection = SweepDirection . CounterClockwise ,
256+ Point = start ,
257+ Size = cornerRadius
258+ }
259+ ]
260+ } ) ;
261+ }
262+ }
263+
264+ /// <summary>
265+ /// Gets the corner flags indicating how an unset symbol is to be processed
266+ /// </summary>
267+ /// <param name="bitMatrix">BitMatrix containing the data</param>
268+ /// <param name="row">The row of the symbol being processed</param>
269+ /// <param name="column">The column of the symbol being processed</param>
270+ /// <returns>The corner flags for an unset symbol</returns>
271+ private static CornerFlags GetUnsetSymbolCornerFlags ( BitMatrix bitMatrix , int row , int column )
272+ {
273+ var flags = CornerFlags . None ;
274+
275+ if ( IsValid ( bitMatrix , column , row ) )
276+ return flags ;
277+
278+ if ( IsValid ( bitMatrix , column , row - 1 ) && IsValid ( bitMatrix , column - 1 , row - 1 ) &&
279+ IsValid ( bitMatrix , column - 1 , row ) )
280+ flags |= CornerFlags . TopLeft ;
281+ if ( IsValid ( bitMatrix , column , row - 1 ) && IsValid ( bitMatrix , column + 1 , row - 1 ) &&
282+ IsValid ( bitMatrix , column + 1 , row ) )
283+ flags |= CornerFlags . TopRight ;
284+ if ( IsValid ( bitMatrix , column , row + 1 ) && IsValid ( bitMatrix , column + 1 , row + 1 ) &&
285+ IsValid ( bitMatrix , column + 1 , row ) )
286+ flags |= CornerFlags . BottomRight ;
287+ if ( IsValid ( bitMatrix , column , row + 1 ) && IsValid ( bitMatrix , column - 1 , row + 1 ) &&
288+ IsValid ( bitMatrix , column - 1 , row ) )
289+ flags |= CornerFlags . BottomLeft ;
290+
291+ return flags ;
292+ }
293+
294+ /// <summary>
295+ /// Returns whether or not the specified symbol should be considered "set"
296+ /// </summary>
297+ /// <param name="bitMatrix">BitMatrix containing the data</param>
298+ /// <param name="x"></param>
299+ /// <param name="y"></param>
300+ /// <returns></returns>
301+ private static bool IsValid ( BitMatrix bitMatrix , int x , int y )
302+ {
303+ // Validate bounds of the bit matrix
304+ if ( x < 0 || y < 0 || x >= bitMatrix . Width || y >= bitMatrix . Height )
305+ return false ;
306+ if ( x < 8 && y < 8 ) return false ;
307+ if ( x > bitMatrix . Width - 9 && y < 8 ) return false ;
308+ if ( x < 8 && y > bitMatrix . Height - 9 ) return false ;
309+ return bitMatrix [ y , x ] ;
310+ }
311+ }
0 commit comments