1
+ #if NETFRAMEWORK || NETSTANDARD2_0
2
+ using System ;
3
+ using System . Collections . Generic ;
4
+ using System . Drawing . Imaging ;
5
+ using System . Globalization ;
6
+ using System . IO ;
7
+ using System . Linq ;
8
+ using static QRCoder . QRCodeGenerator ;
9
+
10
+ /* This renderer is inspired by RemusVasii: https://github.com/codebude/QRCoder/issues/223 */
11
+ namespace QRCoder
12
+ {
13
+
14
+ // ReSharper disable once InconsistentNaming
15
+ public class PdfByteQRCode : AbstractQRCode , IDisposable
16
+ {
17
+ private readonly byte [ ] pdfBinaryComment = new byte [ ] { 0x25 , 0xe2 , 0xe3 , 0xcf , 0xd3 } ;
18
+
19
+ /// <summary>
20
+ /// Constructor without params to be used in COM Objects connections
21
+ /// </summary>
22
+ public PdfByteQRCode ( ) { }
23
+
24
+ public PdfByteQRCode ( QRCodeData data ) : base ( data ) { }
25
+
26
+ /// <summary>
27
+ /// Creates a PDF document with a black & white QR code
28
+ /// </summary>
29
+ /// <param name="pixelsPerModule"></param>
30
+ /// <returns></returns>
31
+ public byte [ ] GetGraphic ( int pixelsPerModule )
32
+ {
33
+ return GetGraphic ( pixelsPerModule , "#000000" , "#ffffff" ) ;
34
+ }
35
+
36
+ /// <summary>
37
+ /// Takes hexadecimal color string #000000 and returns byte[]{ 0, 0, 0 }
38
+ /// </summary>
39
+ /// <param name="colorString">Color in HEX format like #ffffff</param>
40
+ /// <returns></returns>
41
+ private byte [ ] HexColorToByteArray ( string colorString )
42
+ {
43
+ if ( colorString . StartsWith ( "#" ) )
44
+ colorString = colorString . Substring ( 1 ) ;
45
+ byte [ ] byteColor = new byte [ colorString . Length / 2 ] ;
46
+ for ( int i = 0 ; i < byteColor . Length ; i ++ )
47
+ byteColor [ i ] = byte . Parse ( colorString . Substring ( i * 2 , 2 ) , NumberStyles . HexNumber , CultureInfo . InvariantCulture ) ;
48
+ return byteColor ;
49
+ }
50
+
51
+ /// <summary>
52
+ /// Creates a PDF document with given colors DPI and quality
53
+ /// </summary>
54
+ /// <param name="pixelsPerModule"></param>
55
+ /// <param name="darkColorHtmlHex"></param>
56
+ /// <param name="lightColorHtmlHex"></param>
57
+ /// <param name="dpi"></param>
58
+ /// <param name="jpgQuality"></param>
59
+ /// <returns></returns>
60
+ public byte [ ] GetGraphic ( int pixelsPerModule , string darkColorHtmlHex , string lightColorHtmlHex , int dpi = 150 , long jpgQuality = 85 )
61
+ {
62
+ byte [ ] jpgArray = null , pngArray = null ;
63
+ var imgSize = QrCodeData . ModuleMatrix . Count * pixelsPerModule ;
64
+ var pdfMediaSize = ( imgSize * 72 / dpi ) . ToString ( CultureInfo . InvariantCulture ) ;
65
+
66
+ //Get QR code image
67
+ using ( var qrCode = new PngByteQRCode ( QrCodeData ) )
68
+ {
69
+ pngArray = qrCode . GetGraphic ( pixelsPerModule , HexColorToByteArray ( darkColorHtmlHex ) , HexColorToByteArray ( lightColorHtmlHex ) ) ;
70
+ }
71
+
72
+ //Create image and transofrm to JPG
73
+ using ( var msPng = new MemoryStream ( ) )
74
+ {
75
+ msPng . Write ( pngArray , 0 , pngArray . Length ) ;
76
+ var img = System . Drawing . Image . FromStream ( msPng ) ;
77
+ using ( var msJpeg = new MemoryStream ( ) )
78
+ {
79
+ // Create JPEG with specified quality
80
+ var jpgImageCodecInfo = ImageCodecInfo . GetImageEncoders ( ) . First ( x => x . MimeType == "image/jpeg" ) ;
81
+ var jpgEncoderParameters = new EncoderParameters ( 1 ) {
82
+ Param = new EncoderParameter [ ] { new EncoderParameter ( Encoder . Quality , jpgQuality ) }
83
+ } ;
84
+ img . Save ( msJpeg , jpgImageCodecInfo , jpgEncoderParameters ) ;
85
+ jpgArray = msJpeg . ToArray ( ) ;
86
+ }
87
+ }
88
+
89
+ //Create PDF document
90
+ using ( var stream = new MemoryStream ( ) )
91
+ {
92
+ var writer = new StreamWriter ( stream , System . Text . Encoding . GetEncoding ( "ASCII" ) ) ;
93
+
94
+ var xrefs = new List < long > ( ) ;
95
+
96
+ writer . Write ( "%PDF-1.5\r \n " ) ;
97
+ writer . Flush ( ) ;
98
+
99
+ stream . Write ( pdfBinaryComment , 0 , pdfBinaryComment . Length ) ;
100
+ writer . WriteLine ( ) ;
101
+
102
+ writer . Flush ( ) ;
103
+ xrefs . Add ( stream . Position ) ;
104
+
105
+ writer . Write (
106
+ xrefs . Count . ToString ( ) + " 0 obj\r \n " +
107
+ "<<\r \n " +
108
+ "/Type /Catalog\r \n " +
109
+ "/Pages 2 0 R\r \n " +
110
+ ">>\r \n " +
111
+ "endobj\r \n "
112
+ ) ;
113
+
114
+ writer . Flush ( ) ;
115
+ xrefs . Add ( stream . Position ) ;
116
+
117
+ writer . Write (
118
+ xrefs . Count . ToString ( ) + " 0 obj\r \n " +
119
+ "<<\r \n " +
120
+ "/Count 1\r \n " +
121
+ "/Kids [ <<\r \n " +
122
+ "/Type /Page\r \n " +
123
+ "/Parent 2 0 R\r \n " +
124
+ "/MediaBox [0 0 " + pdfMediaSize + " " + pdfMediaSize + "]\r \n " +
125
+ "/Resources << /ProcSet [ /PDF /ImageC ]\r \n " +
126
+ "/XObject << /Im1 4 0 R >> >>\r \n " +
127
+ "/Contents 3 0 R\r \n " +
128
+ ">> ]\r \n " +
129
+ ">>\r \n " +
130
+ "endobj\r \n "
131
+ ) ;
132
+
133
+ var X = "q\r \n " +
134
+ pdfMediaSize + " 0 0 " + pdfMediaSize + " 0 0 cm\r \n " +
135
+ "/Im1 Do\r \n " +
136
+ "Q" ;
137
+
138
+ writer . Flush ( ) ;
139
+ xrefs . Add ( stream . Position ) ;
140
+
141
+ writer . Write (
142
+ xrefs . Count . ToString ( ) + " 0 obj\r \n " +
143
+ "<< /Length " + X . Length . ToString ( ) + " >>\r \n " +
144
+ "stream\r \n " +
145
+ X + "endstream\r \n " +
146
+ "endobj\r \n "
147
+ ) ;
148
+
149
+ writer . Flush ( ) ;
150
+ xrefs . Add ( stream . Position ) ;
151
+
152
+ writer . Write (
153
+ xrefs . Count . ToString ( ) + " 0 obj\r \n " +
154
+ "<<\r \n " +
155
+ "/Name /Im1\r \n " +
156
+ "/Type /XObject\r \n " +
157
+ "/Subtype /Image\r \n " +
158
+ "/Width " + imgSize . ToString ( ) + "/Height " + imgSize . ToString ( ) + "/Length 5 0 R\r \n " +
159
+ "/Filter /DCTDecode\r \n " +
160
+ "/ColorSpace /DeviceRGB\r \n " +
161
+ "/BitsPerComponent 8\r \n " +
162
+ ">>\r \n " +
163
+ "stream\r \n "
164
+ ) ;
165
+ writer . Flush ( ) ;
166
+ stream . Write ( jpgArray , 0 , jpgArray . Length ) ;
167
+ writer . Write (
168
+ "\r \n " +
169
+ "endstream\r \n " +
170
+ "endobj\r \n "
171
+ ) ;
172
+
173
+ writer . Flush ( ) ;
174
+ xrefs . Add ( stream . Position ) ;
175
+
176
+ writer . Write (
177
+ xrefs . Count . ToString ( ) + " 0 obj\r \n " +
178
+ jpgArray . Length . ToString ( ) + " endobj\r \n "
179
+ ) ;
180
+
181
+ writer . Flush ( ) ;
182
+ var startxref = stream . Position ;
183
+
184
+ writer . Write (
185
+ "xref\r \n " +
186
+ "0 " + ( xrefs . Count + 1 ) . ToString ( ) + "\r \n " +
187
+ "0000000000 65535 f\r \n "
188
+ ) ;
189
+
190
+ foreach ( var refValue in xrefs )
191
+ writer . Write ( refValue . ToString ( "0000000000" ) + " 00000 n\r \n " ) ;
192
+
193
+ writer . Write (
194
+ "trailer\r \n " +
195
+ "<<\r \n " +
196
+ "/Size " + ( xrefs . Count + 1 ) . ToString ( ) + "\r \n " +
197
+ "/Root 1 0 R\r \n " +
198
+ ">>\r \n " +
199
+ "startxref\r \n " +
200
+ startxref . ToString ( ) + "\r \n " +
201
+ "%%EOF"
202
+ ) ;
203
+
204
+ writer . Flush ( ) ;
205
+
206
+ stream . Position = 0 ;
207
+
208
+ return stream . ToArray ( ) ;
209
+ }
210
+ }
211
+ }
212
+
213
+ public static class PdfByteQRCodeHelper
214
+ {
215
+ public static byte [ ] GetQRCode ( string plainText , int pixelsPerModule , string darkColorHtmlHex ,
216
+ string lightColorHtmlHex , ECCLevel eccLevel , bool forceUtf8 = false , bool utf8BOM = false ,
217
+ EciMode eciMode = EciMode . Default , int requestedVersion = - 1 )
218
+ {
219
+ using ( var qrGenerator = new QRCodeGenerator ( ) )
220
+ using (
221
+ var qrCodeData = qrGenerator . CreateQrCode ( plainText , eccLevel , forceUtf8 , utf8BOM , eciMode ,
222
+ requestedVersion ) )
223
+ using ( var qrCode = new PdfByteQRCode ( qrCodeData ) )
224
+ return qrCode . GetGraphic ( pixelsPerModule , darkColorHtmlHex , lightColorHtmlHex ) ;
225
+ }
226
+
227
+ public static byte [ ] GetQRCode ( string txt , ECCLevel eccLevel , int size )
228
+ {
229
+ using ( var qrGen = new QRCodeGenerator ( ) )
230
+ using ( var qrCode = qrGen . CreateQrCode ( txt , eccLevel ) )
231
+ using ( var qrBmp = new PdfByteQRCode ( qrCode ) )
232
+ return qrBmp . GetGraphic ( size ) ;
233
+
234
+ }
235
+ }
236
+ }
237
+ #endif
0 commit comments