我编码的风格,先给大家展示下效果图,亲们感觉效果还不错,很满意的话,请继续往下阅读。
之前呢,也写过用安卓实现二维码生成彩色的二维码和带logo的二维码,也知道可以使用qrcode和zxing两种方式,然后这一篇呢也是写二维码使用barcodeformat.qr_code,主要也是看见很多的非常漂亮的二维码,这里呢主要模仿qq的二维码,并且也高仿实现了长按发送给朋友和保存到图库的功能,觉得不错呢就请多支持下,哪里不好呢也可以说出来。好了我们一步一步来。
第一步:简单二维码实现
先来个最简单的二维码:
看下简单代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
/** * 根据指定内容生成自定义宽高的二维码图片 * * @param content * 需要生成二维码的内容 * @param width * 二维码宽度 * @param height * 二维码高度 * @throws writerexception * 生成二维码异常 */ public static bitmap makeqrimage(string content, int width, int height) throws writerexception { hashtable<encodehinttype, string> hints = new hashtable<encodehinttype, string>(); hints.put(encodehinttype.character_set, "utf-8" ); // 图像数据转换,使用了矩阵转换 bitmatrix bitmatrix = new qrcodewriter().encode(content, barcodeformat.qr_code, width, height, hints); int [] pixels = new int [width * height]; // 按照二维码的算法,逐个生成二维码的图片,两个for循环是图片横列扫描的结果 for ( int y = 0 ; y < height; y++) { for ( int x = 0 ; x < width; x++) { if (bitmatrix.get(x, y)) //范围内为黑色的 pixels[y * width + x] = 0xff000000 ; else //其他的地方为白色 pixels[y * width + x] = 0xffffffff ; } } // 生成二维码图片的格式,使用argb_8888 bitmap bitmap = bitmap.createbitmap(width, height, bitmap.config.argb_8888); //设置像素矩阵的范围 bitmap.setpixels(pixels, 0 , width, 0 , 0 , width, height); return bitmap; } |
第二步:简单二维码加logo
接下来给二维码加logo:(看图)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
/** * 根据指定内容生成自定义宽高的二维码图片 * * param logobm * logo图标 * param content * 需要生成二维码的内容 * param width * 二维码宽度 * param height * 二维码高度 * throws writerexception * 生成二维码异常 */ public static bitmap makeqrimage(bitmap logobmp, string content, int qr_width, int qr_height) throws writerexception { try { // 图像数据转换,使用了矩阵转换 hashtable<encodehinttype, object> hints = new hashtable<encodehinttype, object>(); hints.put(encodehinttype.character_set, "utf-8" ); hints.put(encodehinttype.error_correction, errorcorrectionlevel.h); // 容错率 hints.put(encodehinttype.margin, 2 ); // default is 4 hints.put(encodehinttype.max_size, 350 ); hints.put(encodehinttype.min_size, 100 ); bitmatrix bitmatrix = new qrcodewriter().encode(content, barcodeformat.qr_code, qr_width, qr_height, hints); int [] pixels = new int [qr_width * qr_height]; for ( int y = 0 ; y < qr_height; y++) { // 下面这里按照二维码的算法,逐个生成二维码的图片,//两个for循环是图片横列扫描的结果 for ( int x = 0 ; x < qr_width; x++) { if (bitmatrix.get(x, y)) pixels[y * qr_width + x] = 0xff000000 ; else pixels[y * qr_width + x] = 0xffffffff ; } } // ------------------添加图片部分------------------// bitmap bitmap = bitmap.createbitmap(qr_width, qr_height, bitmap.config.argb_8888); // 设置像素点 bitmap.setpixels(pixels, 0 , qr_width, 0 , 0 , qr_width, qr_height); // 获取图片宽高 int logowidth = logobmp.getwidth(); int logoheight = logobmp.getheight(); if (qr_width == 0 || qr_height == 0 ) { return null ; } if (logowidth == 0 || logoheight == 0 ) { return bitmap; } // 图片绘制在二维码中央,合成二维码图片 // logo大小为二维码整体大小的1/2 float scalefactor = qr_width * 1 .0f / 2 / logowidth; try { canvas canvas = new canvas(bitmap); canvas.drawbitmap(bitmap, 0 , 0 , null ); canvas.scale(scalefactor, scalefactor, qr_width / 2 , qr_height / 2 ); canvas.drawbitmap(logobmp, (qr_width - logowidth) / 2 , (qr_height - logoheight) / 2 , null ); canvas.save(canvas.all_save_flag); canvas.restore(); return bitmap; } catch (exception e) { bitmap = null ; e.getstacktrace(); } } catch (writerexception e) { e.printstacktrace(); } return null ; } |
上段代码可以看出要给二维码图片中间加logo,但是图片不能占据整个二维码图片的很大一部分。然后还必须设置容错率:容错率有m,l,q,h几个等级,容错率越高,二维码的有效像素点就越多。这里使用小写的utf-8编码,大写会出现]q2\000026开头内容,为了好看点还设置了边距和大小。
第三步:实现带logo的彩色二维码
接下来我们把黑白矩阵变为彩色矩阵:
就把
1
2
3
4
|
if (bitmatrix.get(x, y)) pixels[y * width + x] = 0xff000000 ; else pixels[y * width + x] = 0xffffffff ; |
替换为:(这里的颜色随便设置,效果随便改)
1
2
3
4
5
6
7
8
9
10
11
12
13
|
if (x < qr_width / 2 && y < qr_height / 2 ) { pixels[y * qr_width + x] = 0xff0094ff ; // 蓝色 integer.tohexstring( new random().nextint()); } else if (x < qr_width / 2 && y > qr_height / 2 ) { pixels[y * qr_width + x] = 0xfffed545 ; // 黄色 } else if (x > qr_width / 2 && y > qr_height / 2 ) { pixels[y * qr_width + x] = 0xff5acf00 ; // 绿色 } else { pixels[y * qr_width + x] = 0xff000000 ; // 黑色 } } else { pixels[y * qr_width + x] = 0xffffffff ; // 白色 } |
改后的效果:
第四步:给二维码加背景
接下来我们来给二维码图片加背景:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/** * 给二维码图片加背景 * */ public static bitmap addbackground(bitmap foreground,bitmap background){ int bgwidth = background.getwidth(); int bgheight = background.getheight(); int fgwidth = foreground.getwidth(); int fgheight = foreground.getheight(); bitmap newmap = bitmap .createbitmap(bgwidth, bgheight, bitmap.config.argb_8888); canvas canvas = new canvas(newmap); canvas.drawbitmap(background, 0 , 0 , null ); canvas.drawbitmap(foreground, (bgwidth - fgwidth) / 2 , (bgheight - fgheight) * 3 / 5 + 70 , null ); canvas.save(canvas.all_save_flag); canvas.restore(); return newmap; } |
这样效果就变为:
第五步:给二维码加水印
然后二维码的个性化制作就最后一步了:加水印,位置随便放
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/** * 在图片右下角添加水印 * * @param srcbmp * 原图 * @param markbmp * 水印图片 * @return 合成水印后的图片 */ public static bitmap composewatermark(bitmap srcbmp, bitmap markbmp) { if (srcbmp == null ) { return null ; } // 创建一个新的和src长度宽度一样的位图 bitmap newb = bitmap.createbitmap(srcbmp.getwidth(), srcbmp.getheight(), bitmap.config.argb_8888); canvas cv = new canvas(newb); // 在 0,0坐标开始画入原图 cv.drawbitmap(srcbmp, 0 , 0 , null ); // 在原图的右下角画入水印 cv.drawbitmap(markbmp, srcbmp.getwidth() - markbmp.getwidth()* 4 / 5 , srcbmp.getheight()* 2 / 7 , null ); // 保存 cv.save(canvas.all_save_flag); // 存储 cv.restore(); return newb; } |
这里贴下实现二维码个性化的完整代码类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
|
package com.ry.personalizedcode.uitls; import android.content.context; import android.graphics.bitmap; import android.graphics.bitmapfactory; import android.graphics.canvas; import com.google.zxing.barcodeformat; import com.google.zxing.encodehinttype; import com.google.zxing.writerexception; import com.google.zxing.common.bitmatrix; import com.google.zxing.qrcode.qrcodewriter; import com.google.zxing.qrcode.decoder.errorcorrectionlevel; import java.util.hashtable; import java.util.random; /** * created on 2016/2/24. * 生成二维码的工具类 */ public class makeqrcodeutil { /** * 根据指定内容生成自定义宽高的二维码图片 * * param logobm * logo图标 * param content * 需要生成二维码的内容 * param width * 二维码宽度 * param height * 二维码高度 * throws writerexception * 生成二维码异常 */ public static bitmap makeqrimage(bitmap logobmp, string content, int qr_width, int qr_height) throws writerexception { try { // 图像数据转换,使用了矩阵转换 hashtable<encodehinttype, object> hints = new hashtable<encodehinttype, object>(); hints.put(encodehinttype.character_set, "utf-8" ); hints.put(encodehinttype.error_correction, errorcorrectionlevel.h); // 容错率 hints.put(encodehinttype.margin, 2 ); // default is 4 hints.put(encodehinttype.max_size, 350 ); hints.put(encodehinttype.min_size, 100 ); bitmatrix bitmatrix = new qrcodewriter().encode(content, barcodeformat.qr_code, qr_width, qr_height, hints); int [] pixels = new int [qr_width * qr_height]; for ( int y = 0 ; y < qr_height; y++) { // 下面这里按照二维码的算法,逐个生成二维码的图片,//两个for循环是图片横列扫描的结果 for ( int x = 0 ; x < qr_width; x++) { if (bitmatrix.get(x, y)) { if (x < qr_width / 2 && y < qr_height / 2 ) { pixels[y * qr_width + x] = 0xff0094ff ; // 蓝色 integer.tohexstring( new random().nextint()); } else if (x < qr_width / 2 && y > qr_height / 2 ) { pixels[y * qr_width + x] = 0xfffed545 ; // 黄色 } else if (x > qr_width / 2 && y > qr_height / 2 ) { pixels[y * qr_width + x] = 0xff5acf00 ; // 绿色 } else { pixels[y * qr_width + x] = 0xff000000 ; // 黑色 } } else { pixels[y * qr_width + x] = 0xffffffff ; // 白色 } } } // ------------------添加图片部分------------------// bitmap bitmap = bitmap.createbitmap(qr_width, qr_height, bitmap.config.argb_8888); // 设置像素点 bitmap.setpixels(pixels, 0 , qr_width, 0 , 0 , qr_width, qr_height); // 获取图片宽高 int logowidth = logobmp.getwidth(); int logoheight = logobmp.getheight(); if (qr_width == 0 || qr_height == 0 ) { return null ; } if (logowidth == 0 || logoheight == 0 ) { return bitmap; } // 图片绘制在二维码中央,合成二维码图片 // logo大小为二维码整体大小的1/2 float scalefactor = qr_width * 1 .0f / 2 / logowidth; try { canvas canvas = new canvas(bitmap); canvas.drawbitmap(bitmap, 0 , 0 , null ); canvas.scale(scalefactor, scalefactor, qr_width / 2 , qr_height / 2 ); canvas.drawbitmap(logobmp, (qr_width - logowidth) / 2 , (qr_height - logoheight) / 2 , null ); canvas.save(canvas.all_save_flag); canvas.restore(); return bitmap; } catch (exception e) { bitmap = null ; e.getstacktrace(); } } catch (writerexception e) { e.printstacktrace(); } return null ; } /** * 获取十六进制的颜色代码.例如 "#6e36b4" , for html , * @return string */ public static string getrandcolorcode(){ string r,g,b; random random = new random(); r = integer.tohexstring(random.nextint( 256 )).touppercase(); g = integer.tohexstring(random.nextint( 256 )).touppercase(); b = integer.tohexstring(random.nextint( 256 )).touppercase(); r = r.length()== 1 ? "0" + r : r ; g = g.length()== 1 ? "0" + g : g ; b = b.length()== 1 ? "0" + b : b ; return r+g+b; } /** * 根据指定内容生成自定义宽高的二维码图片 * * @param content * 需要生成二维码的内容 * @param width * 二维码宽度 * @param height * 二维码高度 * @throws writerexception * 生成二维码异常 */ public static bitmap makeqrimage(string content, int width, int height) throws writerexception { hashtable<encodehinttype, string> hints = new hashtable<encodehinttype, string>(); hints.put(encodehinttype.character_set, "utf-8" ); // 图像数据转换,使用了矩阵转换 bitmatrix bitmatrix = new qrcodewriter().encode(content, barcodeformat.qr_code, width, height, hints); int [] pixels = new int [width * height]; // 按照二维码的算法,逐个生成二维码的图片,两个for循环是图片横列扫描的结果 for ( int y = 0 ; y < height; y++) { for ( int x = 0 ; x < width; x++) { if (bitmatrix.get(x, y)) pixels[y * width + x] = 0xff000000 ; else pixels[y * width + x] = 0xffffffff ; } } // 生成二维码图片的格式,使用argb_8888 bitmap bitmap = bitmap.createbitmap(width, height, bitmap.config.argb_8888); bitmap.setpixels(pixels, 0 , width, 0 , 0 , width, height); return bitmap; } /** * 从资源文件中获取图片 * * @param context * 上下文 * @param drawableid * 资源文件id * @return */ public static bitmap gainbitmap(context context, int drawableid) { bitmap bmp = bitmapfactory.decoderesource(context.getresources(), drawableid); return bmp; } /** * 在图片右下角添加水印 * * @param srcbmp * 原图 * @param markbmp * 水印图片 * @return 合成水印后的图片 */ public static bitmap composewatermark(bitmap srcbmp, bitmap markbmp) { if (srcbmp == null ) { return null ; } // 创建一个新的和src长度宽度一样的位图 bitmap newb = bitmap.createbitmap(srcbmp.getwidth(), srcbmp.getheight(), bitmap.config.argb_8888); canvas cv = new canvas(newb); // 在 0,0坐标开始画入原图 cv.drawbitmap(srcbmp, 0 , 0 , null ); // 在原图的右下角画入水印 cv.drawbitmap(markbmp, srcbmp.getwidth() - markbmp.getwidth()* 4 / 5 , srcbmp.getheight()* 2 / 7 , null ); // 保存 cv.save(canvas.all_save_flag); // 存储 cv.restore(); return newb; } /** * 给二维码图片加背景 * */ public static bitmap addbackground(bitmap foreground,bitmap background){ int bgwidth = background.getwidth(); int bgheight = background.getheight(); int fgwidth = foreground.getwidth(); int fgheight = foreground.getheight(); bitmap newmap = bitmap .createbitmap(bgwidth, bgheight, bitmap.config.argb_8888); canvas canvas = new canvas(newmap); canvas.drawbitmap(background, 0 , 0 , null ); canvas.drawbitmap(foreground, (bgwidth - fgwidth) / 2 , (bgheight - fgheight) * 3 / 5 + 70 , null ); canvas.save(canvas.all_save_flag); canvas.restore(); return newmap; } } |
第六步:给二维码实现长按功能
最后为了模拟下qq的查看二维码名片功能,还加了一个长按弹出actionsheet的功能。
看效果:
具体的 安卓版actionsheet的实现,前面博客有介绍需要的请移步。
这里我们先来实现发送给好友功能:(这里就不做第三方的发送)
1
2
3
4
5
6
7
8
|
private void sendtofriends() { intent intent= new intent(intent.action_send); uri imageuri= uri.parse(environment.getexternalstoragedirectory()+ "/code/qrcode.jpg" ); intent.settype( "image/*" ); intent.putextra(intent.extra_stream, imageuri); intent.setflags(intent.flag_activity_new_task); startactivity(intent.createchooser(intent, gettitle())); } |
发送给朋友效果图:
然后就是要实现保存到本地图库的功能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
/** * 先保存到本地再广播到图库 * */ public static void saveimagetogallery(context context, bitmap bmp) { // 首先保存图片 file appdir = new file(environment.getexternalstoragedirectory(), "code" ); if (!appdir.exists()) { appdir.mkdir(); } string filename = "qrcode.jpg" ; file = new file(appdir, filename); try { fileoutputstream fos = new fileoutputstream(file); bmp.compress(compressformat.jpeg, 100 , fos); fos.flush(); fos.close(); } catch (filenotfoundexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); } // 其次把文件插入到系统图库 try { mediastore.images.media.insertimage(context.getcontentresolver(), file.getabsolutepath(), filename, null ); // 最后通知图库更新 context.sendbroadcast( new intent( intent.action_media_scanner_scan_file, uri.parse( "file://" + file))); } catch (filenotfoundexception e) { e.printstacktrace(); } } |
ps:服务器之家推荐一款在线二维码生成器:https://tool.zzvips.com/t/qrcode/
总结:
这篇说白了就是使用了大量的canvas和bitmap的处理,然后篇幅也是有点长,看起来也是有点累。要看完整的代码请自己下载personalizedcode.rar。下一篇我准备写webview中的二维码图片长按识别二维码功能。