用户端生成二维码 添加到另一张图中去
1、二维码生成
二维码生成用到了Zxing 包,gradle 中引用
compile 'com.google.zxing:core:3.2.1'
生成带有logo的二维码 public class QrCodeUtil{ /** * 黑点颜色 */ private static final int BLACK = 0xFF000000; /** * 白色 */ private static final int WHITE = 0xFFFFFFFF; /** * 正方形二维码宽度 */ private static final int CODE_WIDTH = 180; /** * LOGO宽度值,最大不能大于二维码20%宽度值,大于可能会导致二维码信息失效 */ private static final int LOGO_WIDTH_MAX = CODE_WIDTH / 4; /** *LOGO宽度值,最小不能小于二维码10%宽度值,小于影响Logo与二维码的整体搭配 */ private static final int LOGO_WIDTH_MIN = CODE_WIDTH / 10; /** * 生成的二维码图片存储的URI */ private Uri imageFileUri; /** * 生成带LOGO的二维码 */ public Bitmap createCode(String content, Bitmap logoBitmap) throws WriterException { int logoWidth = logoBitmap.getWidth(); int logoHeight = logoBitmap.getHeight(); int logoHaleWidth = logoWidth >= CODE_WIDTH ? LOGO_WIDTH_MIN : LOGO_WIDTH_MAX; int logoHaleHeight = logoHeight >= CODE_WIDTH ? LOGO_WIDTH_MIN : LOGO_WIDTH_MAX; // 将logo图片按martix设置的信息缩放 Matrix m = new Matrix(); float sx = (float) logoHaleWidth / logoWidth; float sy = (float) logoHaleHeight / logoHeight; m.setScale(sx, sy);// 设置缩放信息 Bitmap newLogoBitmap = Bitmap.createBitmap(logoBitmap, 0, 0, logoWidth, logoHeight, m, false); int newLogoWidth = newLogoBitmap.getWidth(); int newLogoHeight = newLogoBitmap.getHeight(); Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);//设置容错级别,H为最高 hints.put(EncodeHintType.MAX_SIZE, LOGO_WIDTH_MAX);// 设置图片的最大值 hints.put(EncodeHintType.MIN_SIZE, LOGO_WIDTH_MIN);// 设置图片的最小值 hints.put(EncodeHintType.MARGIN, 2);//设置白色边距值 // 生成二维矩阵,编码时指定大小,不要生成了图片以后再进行缩放,这样会模糊导致识别失败 BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_WIDTH, hints); int width = matrix.getWidth(); int height = matrix.getHeight(); int halfW = width / 2; int halfH = height / 2; // 二维矩阵转为一维像素数组,也就是一直横着排了 int[] pixels = new int[width * height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { /* * 取值范围,可以画图理解下 * halfW + newLogoWidth / 2 - (halfW - newLogoWidth / 2) = newLogoWidth * halfH + newLogoHeight / 2 - (halfH - newLogoHeight) = newLogoHeight */ if (x > halfW - newLogoWidth / 2&& x < halfW + newLogoWidth / 2 && y > halfH - newLogoHeight / 2 && y < halfH + newLogoHeight / 2) {// 该位置用于存放图片信息 /* * 记录图片每个像素信息 * halfW - newLogoWidth / 2 < x < halfW + newLogoWidth / 2 * --> 0 < x - halfW + newLogoWidth / 2 < newLogoWidth * halfH - newLogoHeight / 2 < y < halfH + newLogoHeight / 2 * -->0 < y - halfH + newLogoHeight / 2 < newLogoHeight * 刚好取值newLogoBitmap。getPixel(0-newLogoWidth,0-newLogoHeight); */ pixels[y * width + x] = newLogoBitmap.getPixel( x - halfW + newLogoWidth / 2, y - halfH + newLogoHeight / 2); } else { pixels[y * width + x] = matrix.get(x, y) ? BLACK: WHITE;// 设置信息 } } } Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); // 通过像素数组生成bitmap,具体参考api bitmap.setPixels(pixels, 0, width, 0, 0, width, height); return bitmap; } }
2、图片合成,利用canvas合成图片
public class ImageUtil{ public static Bitmap compoundBitmap(Bitmap BitmapOne,Bitmap BitmapTwo){ Bitmap newBitmap = null; newBitmap = Bitmap.createBitmap(BitmapOne); Canvas canvas = new Canvas(newBitmap); Paint paint = new Paint(); int w = BitmapOne.getWidth(); int h = BitmapOne.getHeight(); int w_2 = BitmapTwo.getWidth(); int h_2 = BitmapTwo.getHeight();BitmapOne.getHeight(), paint); paint = new Paint(); //设置第二张图片的 左、上的位置坐标 canvas.drawBitmap(BitmapTwo, 16, h-16-h_2, paint); canvas.save(Canvas.ALL_SAVE_FLAG); // 存储新合成的图片 canvas.restore(); return newBitmap; } }
3、调用,这里第一张图我是从网络取的,所以需要下载图片
//生成二维码 final QrCodeUtil qrCodeUtil = new QrCodeUtil(); try { bitmapQrCode = qrCodeUtil.createCode("https://www.baidu.com/", BitmapFactory.decodeResource(getResources(), R.drawable.finish_icon_highligh)); } catch (WriterException e) { e.printStackTrace(); } //下载网络背景图 Glide.with(CtxHelper.getApp()) .load("//upload-images.jianshu.io/upload_images/2048265-44f59db66cecd375.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240") .asBitmap().into(new SimpleTarget<Bitmap>() { @Override public void onLoadFailed(Exception e, Drawable errorDrawable) { super.onLoadFailed(e, errorDrawable); //下载失败 } @Override public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) { //下载成功 if (bitmapQrCode != null) { //合成图片 Bitmap bitmap = ImageUtils.compoundImage(resource, bitmapQrCode); if (bitmap != null) { //将重新生成的图片显示到界面上 mIvBanner.setImageBitmap(bitmap); } } } });
总结:到这功能就实现了,补充一下图片合成的几种方法:
1、上面例子中的利用canvas画出来
public void compoundImage(View v) { // 防止出现Immutable bitmap passed to Canvas constructor错误 Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.apple).copy(Bitmap.Config.ARGB_8888, true); Bitmap bitmap2 = ((BitmapDrawable) getResources().getDrawable( R.drawable.go)).getBitmap(); Bitmap newBitmap = null; newBitmap = Bitmap.createBitmap(bitmap1); Canvas canvas = new Canvas(newBitmap); Paint paint = new Paint(); int w = bitmap1.getWidth(); int h = bitmap1.getHeight(); int w_2 = bitmap2.getWidth(); int h_2 = bitmap2.getHeight(); paint = new Paint(); // 设置第二张图片的位置 canvas.drawBitmap(bitmap2, Math.abs(w - w_2) / 2, Math.abs(h - h_2) / 2, paint); canvas.save(Canvas.ALL_SAVE_FLAG); // 存储新合成的图片 canvas.restore(); image.setImageBitmap(newBitmap); }
2、使用系统的LayerDrawable类
public void compoundImage(View v) { Bitmap bitmap1 = ((BitmapDrawable) getResources().getDrawable( R.drawable.apple)).getBitmap(); Bitmap bitmap2 = ((BitmapDrawable) getResources().getDrawable( R.drawable.go)).getBitmap(); Drawable[] array = new Drawable[2]; array[0] = new BitmapDrawable(bitmap1); array[1] = new BitmapDrawable(bitmap2); LayerDrawable la = new LayerDrawable(array); // 其中第一个参数为层的索引号,后面的四个参数分别为left、top、right和bottom la.setLayerInset(0, 0, 0, 0, 0); la.setLayerInset(1, 20, 20, 20, 20); image.setImageDrawable(la); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通