二维码生成2

上一篇二维码生成中介绍了通过类库ThoughtWorks.QRCode.dll生成二维码的简单应用,并对类库ThoughtWorks.QRCode.dll做了个简单的封装,这次在上次的基础上做修改,增加了可以在二维码中间增加自定义头像或图标。

下面这篇文章详细介绍了二维码的原理,因为二维码中间大部分区域都是一些无用码,并不影响我们对二维码正常信息的读取,所以我们可以把一张自己的头像,或是公司商标等放在二维码的中间。

http://developer.51cto.com/art/201310/414082_all.htm

要在二维码中间放置商标,而不影响二维码的读取,我们必须设置二维码的纠错级别QRCodeErrorCorrect 为高:

1 _QRCode.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.H;

若不需要中间放图片,正常情况下,我们设置QRCodeErrorCorrect为M即可:

1  _QRCode.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M;

要注意:当 _QRCode.QRCodeErrorCorrect级别不同时,二维码中可以包含的内容长度是不同的:

当 _QRCode.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M时,最多可包含2332个字节数据,最少可包含15个字节数据;

当 _QRCode.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.H时,最多只可包含1274个字节数据,最少可包含8个字节数据;

具体支持多少个字节数据,与属性QRCodeVersion数值有关。

我们可以通过我简单类中的以下几个方法,来设置二维码的中间图片:

 1         /// <summary>
 2         /// 设置二维码中间图片
 3         /// </summary>
 4         /// <param name="fileName">图片文件名,包含路径</param>
 5         public void SetFillImage(string fileName)
 6         {
 7             SetFillImage(fileName, 100, 100);
 8         }
 9         /// <summary>
10         /// 设置二维码中间图片
11         /// </summary>
12         /// <param name="fileName">图片文件名,包含路径</param>
13         /// <param name="width">图片宽度</param>
14         /// <param name="height">图片高度</param>
15         public void SetFillImage(string fileName, int width, int height)
16         {
17             if (!string.IsNullOrEmpty(fileName)) {
18                 if (File.Exists(fileName)) {
19                     SetFillImage(Image.FromFile(fileName), width, height);
20                 }
21             }
22         }
23         /// <summary>
24         /// 设置二维码中间图片
25         /// </summary>
26         /// <param name="bitmap">图上片IMAGE对象</param>
27         public void SetFillImage(Image bitmap)
28         {
29             SetFillImage(bitmap, 100, 100);
30         }
31         /// <summary>
32         /// 设置二维码中间图片
33         /// </summary>
34         /// <param name="bitmap">图上片IMAGE对象</param>
35         /// <param name="width">图片宽度</param>
36         /// <param name="height">图片高度</param>
37         public void SetFillImage(Image bitmap, int width, int height)
38         {
39             fileImage = bitmap;
40             _QRCode.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.H;
41             this._maskWidth = width;
42             this._maskHeight = height;
43         }    

设置图片时,会自动设置QRCodeErrorCorrect 属性为H。

为了保证二维码能正确识别,中间图片的大小最好为二维码大小的1/3到3/7之间,我设置为1/3大小的样子:

1         int maskWidth = Math.Min((int)(this.Width / 3), _maskWidth);     //最终图片宽度
2         int maskHeight = Math.Min((int)(this.Height / 3), _maskHeight);  //最终图片高度
3 
4         int maskLeft = (this.Width - maskWidth) / 2;             //图片位置
5         int maskTop = (this.Height - maskHeight) / 2;                  //图片位置

这样在调用Encode方法生成二维码时,会自动将设置好的图片放到二维码的中间。

具体调用方法:

1             ErWeiMa.ErWeiMa er = new ErWeiMa.ErWeiMa();
2             er.SetFillImage(Server.MapPath("~/t.jpg"));
3             this.img1.Src = er.Encode("中华人民共和国");        

生成的二维码如下所示:

源代码:

  1     public class ErWeiMa
  2     {
  3         private QRCodeEncoder _QRCode;
  4         private Encoding encoding;
  5 
  6         public ErWeiMa()
  7         {
  8             _QRCode = new QRCodeEncoder();
  9             _QRCode.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;
 10             _QRCode.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M;
 11             _QRCode.QRCodeScale = 4;
 12 
 13             encoding = Encoding.UTF8;
 14         }
 15 
 16         public static ErWeiMa GetInstance()
 17         {
 18             return new ErWeiMa();
 19         }
 20 
 21         /// <summary>
 22         /// 获取二维码图像base64字符串,可直接赋值给img对象的src显示
 23         /// 默认编码UTF8,QRCodeEncoder默认值为Unicode
 24         /// </summary>
 25         /// <param name="content">编码内容</param>
 26         /// <returns>二维码图像base64字符串</returns>
 27         public string Encode(string content)
 28         {
 29             return this.Encode(content, encoding);
 30         }
 31         /// <summary>
 32         /// 获取二维码图像base64字符串,可直接赋值给img对象的src显示
 33         /// </summary>
 34         /// <param name="content">编码内容</param>
 35         /// <param name="encoding">编码类型</param>
 36         /// <returns>二维码图像base64字符串</returns>
 37         public string Encode(string content,Encoding encoding)
 38         {
 39             this.encoding = encoding;
 40             this.InitVersion(content);
 41             using (var ms = new MemoryStream())
 42             using (Bitmap image = _QRCode.Encode(content, encoding))
 43             {
 44                 this.Width = image.Width;
 45                 this.Height = image.Height;
 46                 FileImage(image);
 47                 image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
 48                 return "data:image/jpeg;base64," + Convert.ToBase64String(ms.ToArray());
 49             }
 50         }
 51 
 52         private void FileImage(Bitmap source)
 53         {
 54             int maskWidth = Math.Min((int)(this.Width / 3), _maskWidth);
 55             int maskHeight = Math.Min((int)(this.Height / 3), _maskHeight);
 56 
 57             int maskLeft = (this.Width - maskWidth) / 2;
 58             int maskTop = (this.Height - maskHeight) / 2;
 59 
 60             using (Graphics g = Graphics.FromImage(source))
 61             {
 62                 g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
 63                 g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
 64                 g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
 65                 //g.FillRectangle(new SolidBrush(Color.Red), maskLeft, maskTop, maskWidth, maskHeight);
 66                 ////g.DrawImage(
 67                 if (fileImage != null) {
 68                     g.DrawImage(fileImage, maskLeft, maskTop, maskWidth, maskHeight);
 69                 }
 70             }
 71         }
 72 
 73         /// <summary>
 74         /// 根据编码内容自动获取QRCodeVersion值
 75         /// </summary>
 76         /// <param name="content"></param>
 77         private void InitVersion(string content)
 78         {
 79             int length = encoding.GetByteCount(content);
 80 
 81             if (length > GetArray()[40]) {
 82                 throw new Exception("The content too length;Must be shorter than " + GetArray()[40].ToString() + "byte"); ;
 83             }
 84 
 85             _QRCode.QRCodeVersion = GetIndex(length);
 86         }
 87 
 88         /// <summary>
 89         /// 每个QRCodeVersion值对应支持最长字节数
 90         /// </summary>
 91         private int[] array = new int[41] {15,15,27,43,63,85,107,123,153,181,214,252,288,332,363,413,451,505,561,625,667,712,780,858,912,998,1060,1126,1191,1265,1371,1453,1539,1629,1723,1810,1912,1990,2100,2214,2332 };
 92         /// <summary>
 93         /// QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.H时 每个QRCodeVersion值对应支持最长字节数
 94         /// </summary>
 95         private int[] array2 = new int[41] { 8, 8, 15, 25, 35, 45, 59, 65, 85, 99, 120, 138, 156, 178, 195, 221, 251, 281, 311, 339, 383, 404, 440, 462, 512, 536, 594, 626, 659, 699, 743, 791, 843, 899, 959, 984, 1052, 1094, 1140, 1220, 1274 };
 96 
 97         private int[] GetArray()
 98         {
 99             switch (_QRCode.QRCodeErrorCorrect)
100             {
101                 case QRCodeEncoder.ERROR_CORRECTION.H:
102                     return array2;
103                 case QRCodeEncoder.ERROR_CORRECTION.M:
104                     return array;
105                 default:
106                     return array;
107             }
108         }
109 
110         private int GetIndex(int length)
111         {
112             if (length <= GetArray()[0]) {
113                 return 0;
114             }
115             if (length == GetArray()[40]) {
116                 return 40;
117             }
118 
119             return FindIndex(GetArray(), length, 0, 40);
120         }
121 
122         private int FindIndex(int[] sourceArray, int findValue, int startIndex, int endIndex)
123         {
124             int mid = (startIndex + endIndex) % 2 == 0 ? (startIndex + endIndex) / 2 : (startIndex + endIndex) / 2 + 1;
125 
126             if (startIndex >= endIndex) {
127                 return startIndex;
128             }
129 
130             if (findValue == sourceArray[mid])
131             {
132                 return mid;
133             }
134             else if (findValue < sourceArray[mid])
135             {
136                 if (findValue > sourceArray[mid - 1])
137                 {
138                     return mid;
139                 }
140                 return FindIndex(sourceArray,findValue, startIndex, mid - 1);
141             }
142             else {
143                 if (findValue < sourceArray[mid + 1])
144                 {
145                     return mid + 1;
146                 }
147                 return FindIndex(sourceArray,findValue, mid + 1, endIndex);
148             }
149         }
150 
151         private Image fileImage = null;
152 
153         /// <summary>
154         /// 设置二维码中间图片
155         /// </summary>
156         /// <param name="fileName">图片文件名,包含路径</param>
157         public void SetFillImage(string fileName)
158         {
159             SetFillImage(fileName, 100, 100);
160         }
161         /// <summary>
162         /// 设置二维码中间图片
163         /// </summary>
164         /// <param name="fileName">图片文件名,包含路径</param>
165         /// <param name="width">图片宽度</param>
166         /// <param name="height">图片高度</param>
167         public void SetFillImage(string fileName, int width, int height)
168         {
169             if (!string.IsNullOrEmpty(fileName)) {
170                 if (File.Exists(fileName)) {
171                     SetFillImage(Image.FromFile(fileName), width, height);
172                 }
173             }
174         }
175         /// <summary>
176         /// 设置二维码中间图片
177         /// </summary>
178         /// <param name="bitmap">图上片IMAGE对象</param>
179         public void SetFillImage(Image bitmap)
180         {
181             SetFillImage(bitmap, 100, 100);
182         }
183         /// <summary>
184         /// 设置二维码中间图片
185         /// </summary>
186         /// <param name="bitmap">图上片IMAGE对象</param>
187         /// <param name="width">图片宽度</param>
188         /// <param name="height">图片高度</param>
189         public void SetFillImage(Image bitmap, int width, int height)
190         {
191             fileImage = bitmap;
192             _QRCode.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.H;
193             this._maskWidth = width;
194             this._maskHeight = height;
195         }
196         /// <summary>
197         /// 生成的二维码宽度
198         /// </summary>
199         public int Width { get; set; }
200         /// <summary>
201         /// 生成的二维码高度
202         /// </summary>
203         public int Height { get; set; }
204 
205         private int _maskWidth = 0;
206         private int _maskHeight = 0;
207     }
View Code

ThoughtWorks.QRCode.dll类库地址,请参见我上一篇笔记。

如果写的内容对你有所帮助,请帮我点个赞吧,你的鼓励是对我最大的支持和动力
原文地址:https://www.cnblogs.com/maerge/p/6445545.html