效果图
1.引入pom
<dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.3.3</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.3.3</version> </dependency>
2.工具类
import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.WriterException; import com.google.zxing.client.j2se.MatrixToImageWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import sun.misc.BASE64Encoder; import javax.imageio.ImageIO; import javax.imageio.stream.ImageOutputStream; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import java.util.HashMap; import java.util.Map; import java.util.Objects; /** * @description :ZxingUtils * @author :liu * @since :2021/12/1 16:40 */ public class ZxingUtils { public static BufferedImage enQRCode(String contents, int width, int height) throws WriterException { //定义二维码参数 final Map<EncodeHintType, Object> hints = new HashMap(8) { { //编码 put(EncodeHintType.CHARACTER_SET, "UTF-8"); //容错级别 put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //边距 put(EncodeHintType.MARGIN, 0); } }; return enQRCode(contents, width, height, hints); } /** * 生成二维码 * @param contents 二维码内容 * @param width 图片宽度 * @param height 图片高度 * @param hints 二维码相关参数 * @return BufferedImage对象 * @throws WriterException 编码时出错 * @throws IOException 写入文件出错 */ public static BufferedImage enQRCode(String contents, int width, int height, Map hints) throws WriterException { // String uuid = UUID.randomUUID().toString().replace("-", ""); //本地完整路径 // String pathname = path + "/" + uuid + "." + format; //生成二维码 BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints); // Path file = new File(pathname).toPath(); //将二维码保存到路径下 // MatrixToImageWriter.writeToPa(bitMatrix, format, file); // return pathname; return MatrixToImageWriter.toBufferedImage(bitMatrix); } /** * 将图片绘制在背景图上 * * @param backgroundPath 背景图路径 * @param zxingImage 图片 * @param x 图片在背景图上绘制的x轴起点 * @param y 图片在背景图上绘制的y轴起点 * @return */ public static BufferedImage drawImage(String backgroundPath, BufferedImage zxingImage, int x, int y) throws IOException { //读取背景图的图片流 BufferedImage backgroundImage; //Try-with-resources 资源自动关闭,会自动调用close()方法关闭资源,只限于实现Closeable或AutoCloseable接口的类 try (InputStream imagein = new FileInputStream(backgroundPath)) { backgroundImage = ImageIO.read(imagein); } return drawImage(backgroundImage, zxingImage, x, y); } /** * 将图片绘制在背景图上 * * @param backgroundImage 背景图 * @param zxingImage 图片 * @param x 图片在背景图上绘制的x轴起点 * @param y 图片在背景图上绘制的y轴起点 * @return * @throws IOException */ public static BufferedImage drawImage(BufferedImage backgroundImage, BufferedImage zxingImage, int x, int y) throws IOException { Objects.requireNonNull(backgroundImage, ">>>>>背景图不可为空"); Objects.requireNonNull(zxingImage, ">>>>>二维码不可为空"); //二维码宽度+x不可以超过背景图的宽度,长度同理 if ((zxingImage.getWidth() + x) > backgroundImage.getWidth() || (zxingImage.getHeight() + y) > backgroundImage.getHeight()) { throw new IOException(">>>>>二维码宽度+x不可以超过背景图的宽度,长度同理"); } //合并图片 Graphics2D g = backgroundImage.createGraphics(); g.drawImage(zxingImage, x, y, zxingImage.getWidth(), zxingImage.getHeight(), null); return backgroundImage; } public static InputStream bufferedImageToInputStream(BufferedImage backgroundImage) throws IOException { return bufferedImageToInputStream(backgroundImage, "png"); } /** * backgroundImage 转换为输出流 * * @param backgroundImage * @param format * @return * @throws IOException */ public static InputStream bufferedImageToInputStream(BufferedImage backgroundImage, String format) throws IOException { ByteArrayOutputStream bs = new ByteArrayOutputStream(); try ( ImageOutputStream imOut = ImageIO.createImageOutputStream(bs)) { ImageIO.write(backgroundImage, format, imOut); InputStream is = new ByteArrayInputStream(bs.toByteArray()); return is; } } /** * 保存为文件 * * @param is * @param fileName * @throws IOException */ public static void saveFile(InputStream is, String fileName) throws IOException { try (BufferedInputStream in = new BufferedInputStream(is); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(fileName))) { int len; byte[] b = new byte[1024]; while ((len = in.read(b)) != -1) { out.write(b, 0, len); } } } public static void main(String[] args) { //二维码宽度 int width = 230; //二维码高度 int height = 177; //二维码内容 String contcent = "XXXXXXXXXXXXXXXXXXXXxxx;"; BufferedImage zxingImage = null; try { //二维码图片流 zxingImage = ZxingUtils.enQRCode(contcent, width, height); } catch (WriterException e) { e.printStackTrace(); } //背景图片地址 String backgroundPath = "C:/Users/pc/Desktop/baseProve.png"; InputStream inputStream = null; try { //合成二维码和背景图 BufferedImage image = ZxingUtils.drawImage(backgroundPath, zxingImage, 548, 0); //绘制文字 Font font = new Font("微软雅黑", Font.PLAIN, 20); String text = "xxxxxxxxxxxx"; image = ZxingUtils.drawString(image, text, 185, 195,font,new Color(0,0,0)); //绘制文字 Font font2 = new Font("微软雅黑", Font.PLAIN, 20); String text2 = "2017"; image = ZxingUtils.drawString(image, text2, 245, 252,font2,new Color(0,0,0)); //绘制文字 Font font3 = new Font("微软雅黑", Font.PLAIN, 20); String text3 = "2017-10-04 19:07:27"; image = ZxingUtils.drawString(image, text3, 450, 402,font3,new Color(0,0,0)); //添加水印 Font font4 = new Font("微软雅黑", Font.PLAIN, 60); //水印字体 Color color=new Color(0,0,0,15); String waterMarkContent="http://www.gdstcloud.com"; //水印内容//水印图片色彩以及透明度50, 270, image=ZxingUtils.addWaterMarkIO(image, waterMarkContent,50, 270, font4, color); ByteArrayOutputStream out = new ByteArrayOutputStream(); //转换成png格式的IO流 ImageIO.write(image, "png", out); byte[] bytes = out.toByteArray(); // 2、将字节数组转为二进制 BASE64Encoder encoder = new BASE64Encoder(); String binary = encoder.encodeBuffer(bytes).trim(); //图片转inputStream inputStream = ZxingUtils.bufferedImageToInputStream(image); } catch (IOException e) { e.printStackTrace(); } //保存的图片路径 String originalFileName= "E:/asd/99.png"; try { //保存为本地图片 ZxingUtils.saveFile(inputStream, originalFileName); System.out.println("成功!"); } catch (IOException e) { e.printStackTrace(); } } /** * 将文字绘制在背景图上 * * @param backgroundImage 背景图 * @param x 文字在背景图上绘制的x轴起点 * @param y 文字在背景图上绘制的y轴起点 * @return * @throws IOException */ public static BufferedImage drawString(BufferedImage backgroundImage, String text, int x, int y,Font font,Color color) { //绘制文字 Graphics2D g = backgroundImage.createGraphics(); //设置颜色 g.setColor(color); //消除锯齿状 g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); //设置字体 g.setFont(font); //绘制文字 g.drawString(text, x, y); return backgroundImage; } /** * 将水印绘制在背景图上 * @param backgroundImage 背景图 * @param waterMarkContent 内容 * @param x 文字在背景图上绘制的x轴起点 * @param y 文字在背景图上绘制的y轴起点 * @param font 设置字体 * @param color 图片的背景设置水印颜色 * @return */ public static BufferedImage addWaterMarkIO(BufferedImage backgroundImage, String waterMarkContent,int x,int y,Font font,Color color) { int srcImgWidth = backgroundImage.getWidth(null);//获取图片的宽 int srcImgHeight = backgroundImage.getHeight(null);//获取图片的高 // 加水印 Graphics2D g = backgroundImage.createGraphics(); g.drawImage(backgroundImage, 0, 0, srcImgWidth, srcImgHeight, null); g.setColor(color); //根据图片的背景设置水印颜色 g.setFont(font); //设置字体 //设置水印的坐标 //int x = srcImgWidth - getWatermarkLengths(waterMarkContent, g); //int y = srcImgHeight - getWatermarkLengths(waterMarkContent, g); /* int x = 50; int y = 270; */ // 设置水印旋转 g.rotate(Math.toRadians(20),backgroundImage.getWidth() / 2, (double) backgroundImage .getHeight() / 2); g.drawString(waterMarkContent, x, y); //画出水印 g.dispose(); return backgroundImage; } /** * 计算随意坐标 * @param waterMarkContent * @param g * @return */ public static int getWatermarkLengths(String waterMarkContent, Graphics2D g) { return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length()); } /** * @param srcImgPath 源图片路径 * @param tarImgPath 保存的图片路径 * @param waterMarkContent 水印内容 * @param markContentColor 水印颜色 * @param font 水印字体 */ public void addWaterMark(String srcImgPath, String tarImgPath, String waterMarkContent,Color markContentColor,Font font) { try { // 读取原图片信息 File srcImgFile = new File(srcImgPath);//得到文件 Image srcImg = ImageIO.read(srcImgFile);//文件转化为图片 int srcImgWidth = srcImg.getWidth(null);//获取图片的宽 int srcImgHeight = srcImg.getHeight(null);//获取图片的高 // 加水印 BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g = bufImg.createGraphics(); g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null); g.setColor(markContentColor); //根据图片的背景设置水印颜色 g.setFont(font); //设置字体 //设置水印的坐标 /* int x = srcImgWidth - getWatermarkLength(waterMarkContent, g); int y = srcImgHeight - getWatermarkLength(waterMarkContent, g); */ int x = 50; int y = 270; // 设置水印旋转 g.rotate(Math.toRadians(20),bufImg.getWidth() / 2, (double) bufImg .getHeight() / 2); g.drawString(waterMarkContent, x, y); //画出水印 g.dispose(); // 输出图片 FileOutputStream outImgStream = new FileOutputStream(tarImgPath); ImageIO.write(bufImg, "jpg", outImgStream); System.out.println("添加水印完成"); outImgStream.flush(); outImgStream.close(); } catch (Exception e) { // TODO: handle exception } } public int getWatermarkLength(String waterMarkContent, Graphics2D g) { return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length()); } public static void main1(String[] args) { Font font = new Font("微软雅黑", Font.PLAIN, 60); //水印字体 String srcImgPath="E:/99999.png"; //源图片地址 String tarImgPath="E:/999998.png"; //待存储的地址 String waterMarkContent="http://www.baidu.com"; //水印内容 Color color=new Color(0,0,0,15); //水印图片色彩以及透明度 new ZxingUtils().addWaterMark(srcImgPath, tarImgPath, waterMarkContent, color,font); } }
3.controller类下载二维码
/** * 下载 */ @RequestMapping(value="/downLoadBaseProve") public void downLoadBaseProve(HttpServletResponse response, HttpServletRequest request) throws Exception{ /** 省略 */ BASE64Decoder decoder = new BASE64Decoder(); String images=getbaseProveIo(); byte[] bytes1 = decoder.decodeBuffer(images); String name= "xxx-停车场"+ System.currentTimeMillis()+".png"; // byte[] bytes = Files.readAllBytes(file.toPath()); // // String name = file.getName(); name = URLEncoder.encode(name, "UTF-8"); response.reset(); response.setHeader("Content-Disposition", "attachment; filename=\"" + name + "\""); response.addHeader("Content-Length", "" + bytes1.length); response.setContentType("application/octet-stream;charset=UTF-8"); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream()); outputStream.write(bytes1); outputStream.flush(); outputStream.close(); response.flushBuffer(); }
方法:
private String getbaseProveIo() throws IOException { // int num="55"; String binary=null; //背景图片地址 File f = new ClassPathResource("qrTpl/wx_pay_tpl.png").getFile(); String imagein = f.getAbsolutePath(); //InputStream imageins = new FileInputStream(imagein); System.out.println(imagein); //二维码宽度 int width = 669; //二维码高度 int height = 681; //二维码内容 String contcent = "?parkId=16&channelNo=2"; BufferedImage zxingImage = null; try { //二维码图片流 zxingImage = ZxingUtils.enQRCode(contcent, width, height); } catch (WriterException e) { e.printStackTrace(); } try { //合成二维码和背景图 BufferedImage image = ZxingUtils.drawImage(imagein, zxingImage, 313, 569); //绘制文字 // Font font = new Font("微软雅黑", Font.PLAIN, 20); // String text = "中国"; // image = ZxingUtils.drawString(image, text, 185, 195,font,new Color(0,0,0)); //绘制文字 // Font font2 = new Font("微软雅黑", Font.PLAIN, 20); // String text2 = DateUtil.today(); // image = ZxingUtils.drawString(image, text2, 245, 252,font2,new Color(0,0,0)); //绘制文字 Font font3 = new Font("微软雅黑", Font.PLAIN, 72); String text3 = "xxx-停车场"; image = ZxingUtils.drawString(image, text3, 81, 101,font3,new Color(255,255,255)); //添加水印 Font font4 = new Font("微软雅黑", Font.PLAIN, 60); //水印字体 Color color=new Color(0,0,0,15); String waterMarkContent="深圳xxx科技有限公司"; //水印内容//水印图片色彩以及透明度50, 270, image=ZxingUtils.addWaterMarkIO(image, waterMarkContent,215, 183, font4, color); //图片以字节数据在页面显示 ByteArrayOutputStream out = new ByteArrayOutputStream(); //转换成png格式的IO流 ImageIO.write(image, "png", out); byte[] bytes = out.toByteArray(); // 2、将字节数组转为二进制 BASE64Encoder encoder = new BASE64Encoder(); binary = encoder.encodeBuffer(bytes).trim(); //图片转inputStream //inputStream = ZxingUtils.bufferedImageToInputStream(image); } catch (IOException e) { e.printStackTrace(); } return binary; }
之后就可以在页面下载合成后的二维码
参考:java 生成二维码,并跟其他图合成新图 图片添加水印_冰夜翎博客-CSDN博客