基于Android实现个性彩色好看的二维码
我编码的风格,先给大家展示下效果图,亲们感觉效果还不错,很满意的话,请继续往下阅读。
之前呢,也写过用安卓实现二维码生成彩色的二维码和带logo的二维码,也知道可以使用qrcode和zxing两种方式,然后这一篇呢也是写二维码使用barcodeformat.qr_code,主要也是看见很多的非常漂亮的二维码,这里呢主要模仿qq的二维码,并且也高仿实现了长按发送给朋友和保存到图库的功能,觉得不错呢就请多支持下,哪里不好呢也可以说出来。好了我们一步一步来。
第一步:简单二维码实现
先来个最简单的二维码:
看下简单代码实现:
/** * 根据指定内容生成自定义宽高的二维码图片 * * @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:(看图)
/** * 根据指定内容生成自定义宽高的二维码图片 * * 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的彩色二维码
接下来我们把黑白矩阵变为彩色矩阵:
就把
if (bitmatrix.get(x, y)) pixels[y * width + x] = 0xff000000; else pixels[y * width + x] = 0xffffffff;
替换为:(这里的颜色随便设置,效果随便改)
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;// 白色 }
改后的效果:
第四步:给二维码加背景
接下来我们来给二维码图片加背景:
/** * 给二维码图片加背景 * */ 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; }
这样效果就变为:
第五步:给二维码加水印
然后二维码的个性化制作就最后一步了:加水印,位置随便放
/** * 在图片右下角添加水印 * * @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; }
这里贴下实现二维码个性化的完整代码类:
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的实现,前面博客有介绍需要的请移步。
这里我们先来实现发送给好友功能:(这里就不做第三方的发送)
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())); }
发送给朋友效果图:
然后就是要实现保存到本地图库的功能:
/** * 先保存到本地再广播到图库 * */ 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(); } }
总结:
这篇说白了就是使用了大量的canvas和bitmap的处理,然后篇幅也是有点长,看起来也是有点累。要看完整的代码请自己下载personalizedcode.rar。下一篇我准备写webview中的二维码图片长按识别二维码功能。
上一篇: FPGA三人表决器问题总结
下一篇: systemctl 编辑器更改为 vim