1
+ #if NETFRAMEWORK || NETSTANDARD2_0 || NET5_0
2
+
3
+ using System ;
4
+ using System . Drawing ;
5
+ using System . Drawing . Drawing2D ;
6
+
7
+ // pull request raised to extend library used.
8
+ namespace QRCoder
9
+ {
10
+ public class ArtQRCode : AbstractQRCode , IDisposable
11
+ {
12
+ /// <summary>
13
+ /// Constructor without params to be used in COM Objects connections
14
+ /// </summary>
15
+ public ArtQRCode ( ) { }
16
+
17
+ public ArtQRCode ( QRCodeData data ) : base ( data ) { }
18
+
19
+ public Bitmap GetGraphic ( int pixelsPerModule )
20
+ {
21
+ return this . GetGraphic ( pixelsPerModule , ( pixelsPerModule * 8 ) / 10 , Color . Black , Color . White ) ;
22
+ }
23
+
24
+ public Bitmap GetGraphic ( Bitmap backgroundImage = null )
25
+ {
26
+ return this . GetGraphic ( 10 , 7 , Color . Black , Color . White , backgroundImage : backgroundImage ) ;
27
+ }
28
+
29
+ public Bitmap GetGraphic (
30
+ int pixelsPerModule ,
31
+ int pixelSize ,
32
+ Color darkColor ,
33
+ Color lightColor ,
34
+ bool drawQuietZones = false ,
35
+ Bitmap reticleImage = null ,
36
+ Bitmap backgroundImage = null )
37
+ {
38
+ var numModules = this . QrCodeData . ModuleMatrix . Count - ( drawQuietZones ? 0 : 8 ) ;
39
+ var offset = ( drawQuietZones ? 0 : 4 ) ;
40
+ var size = numModules * pixelsPerModule ;
41
+
42
+ var bitmap = Resize ( backgroundImage , size ) ?? new Bitmap ( size , size ) ;
43
+
44
+ using ( var graphics = Graphics . FromImage ( bitmap ) )
45
+ {
46
+ using ( var lightBrush = new SolidBrush ( lightColor ) )
47
+ {
48
+ using ( var darkBrush = new SolidBrush ( darkColor ) )
49
+ {
50
+ // make background transparent if you don't have an image -- not sure this is needed
51
+ if ( backgroundImage == null )
52
+ {
53
+ using ( var brush = new SolidBrush ( Color . Transparent ) )
54
+ {
55
+ graphics . FillRectangle ( brush , new Rectangle ( 0 , 0 , size , size ) ) ;
56
+ }
57
+ }
58
+
59
+ var darkModulePixel = MakeDotPixel ( pixelsPerModule , pixelSize , darkBrush ) ;
60
+ var lightModulePixel = MakeDotPixel ( pixelsPerModule , pixelSize , lightBrush ) ;
61
+
62
+ for ( var x = 0 ; x < numModules ; x += 1 )
63
+ {
64
+ for ( var y = 0 ; y < numModules ; y += 1 )
65
+ {
66
+ var rectangleF = new Rectangle ( x * pixelsPerModule , y * pixelsPerModule , pixelsPerModule , pixelsPerModule ) ;
67
+
68
+ var pixelIsDark = this . QrCodeData . ModuleMatrix [ offset + y ] [ offset + x ] ;
69
+ var solidBrush = pixelIsDark ? darkBrush : lightBrush ;
70
+ var pixelImage = pixelIsDark ? darkModulePixel : lightModulePixel ;
71
+
72
+ if ( ! IsPartOfReticle ( x , y , numModules , offset ) )
73
+ graphics . DrawImage ( pixelImage , rectangleF ) ;
74
+ else if ( reticleImage == null )
75
+ graphics . FillRectangle ( solidBrush , rectangleF ) ;
76
+ }
77
+ }
78
+
79
+ if ( reticleImage != null )
80
+ {
81
+ var reticleSize = 7 * pixelsPerModule ;
82
+ graphics . DrawImage ( reticleImage , new Rectangle ( 0 , 0 , reticleSize , reticleSize ) ) ;
83
+ graphics . DrawImage ( reticleImage , new Rectangle ( size - reticleSize , 0 , reticleSize , reticleSize ) ) ;
84
+ graphics . DrawImage ( reticleImage , new Rectangle ( 0 , size - reticleSize , reticleSize , reticleSize ) ) ;
85
+ }
86
+
87
+ graphics . Save ( ) ;
88
+ }
89
+ }
90
+ }
91
+ return bitmap ;
92
+ }
93
+
94
+ /// <summary>
95
+ /// If the pixelSize is bigger than the pixelsPerModule or may end up filling the Module making a traditional QR code.
96
+ /// </summary>
97
+ /// <param name="pixelsPerModule"></param>
98
+ /// <param name="pixelSize"></param>
99
+ /// <param name="brush"></param>
100
+ /// <returns></returns>
101
+ private Bitmap MakeDotPixel ( int pixelsPerModule , int pixelSize , SolidBrush brush )
102
+ {
103
+ // draw a dot
104
+ var bitmap = new Bitmap ( pixelSize , pixelSize ) ;
105
+ using ( var graphics = Graphics . FromImage ( bitmap ) )
106
+ {
107
+ graphics . FillEllipse ( brush , new Rectangle ( 0 , 0 , pixelSize , pixelSize ) ) ;
108
+ graphics . Save ( ) ;
109
+ }
110
+
111
+ var pixelWidth = Math . Min ( pixelsPerModule , pixelSize ) ;
112
+ var margin = Math . Max ( ( pixelsPerModule - pixelWidth ) / 2 , 0 ) ;
113
+
114
+ // center the dot in the module and crop to stay the right size.
115
+ var cropped = new Bitmap ( pixelsPerModule , pixelsPerModule ) ;
116
+ using ( var graphics = Graphics . FromImage ( cropped ) )
117
+ {
118
+ graphics . DrawImage ( bitmap , new Rectangle ( margin , margin , pixelWidth , pixelWidth ) ,
119
+ new RectangleF ( ( ( float ) pixelSize - pixelWidth ) / 2 , ( ( float ) pixelSize - pixelWidth ) / 2 , pixelWidth , pixelWidth ) ,
120
+ GraphicsUnit . Pixel ) ;
121
+ graphics . Save ( ) ;
122
+ }
123
+
124
+ return cropped ;
125
+ }
126
+
127
+ private bool IsPartOfReticle ( int x , int y , int numModules , int offset )
128
+ {
129
+ var cornerSize = 11 - offset ;
130
+ return
131
+ ( x < cornerSize && y < cornerSize ) ||
132
+ ( x > ( numModules - cornerSize - 1 ) && y < cornerSize ) ||
133
+ ( x < cornerSize && y > ( numModules - cornerSize - 1 ) ) ;
134
+ }
135
+
136
+ /// <summary>
137
+ /// Resize to a square bitmap, but maintain the aspect ratio by padding transparently.
138
+ /// </summary>
139
+ ///
140
+ /// <param name="image"></param>
141
+ /// <param name="newSize"></param>
142
+ /// <returns></returns>
143
+ private Bitmap Resize ( Bitmap image , int newSize )
144
+ {
145
+ if ( image == null ) return null ;
146
+
147
+ float scale = Math . Min ( ( float ) newSize / image . Width , ( float ) newSize / image . Height ) ;
148
+ var scaledWidth = ( int ) ( image . Width * scale ) ;
149
+ var scaledHeight = ( int ) ( image . Height * scale ) ;
150
+ var offsetX = ( newSize - scaledWidth ) / 2 ;
151
+ var offsetY = ( newSize - scaledHeight ) / 2 ;
152
+
153
+ var scaledImage = new Bitmap ( image , new Size ( scaledWidth , scaledHeight ) ) ;
154
+
155
+ var bm = new Bitmap ( newSize , newSize ) ;
156
+
157
+ using ( Graphics graphics = Graphics . FromImage ( bm ) )
158
+ {
159
+ using ( var brush = new SolidBrush ( Color . Transparent ) )
160
+ {
161
+ graphics . FillRectangle ( brush , new Rectangle ( 0 , 0 , newSize , newSize ) ) ;
162
+
163
+ graphics . InterpolationMode = InterpolationMode . High ;
164
+ graphics . CompositingQuality = CompositingQuality . HighQuality ;
165
+ graphics . SmoothingMode = SmoothingMode . AntiAlias ;
166
+
167
+ graphics . DrawImage ( scaledImage , new Rectangle ( offsetX , offsetY , scaledWidth , scaledHeight ) ) ;
168
+ }
169
+ }
170
+
171
+ return bm ;
172
+ }
173
+ }
174
+ }
175
+
176
+ #endif
0 commit comments