应公司需求,要求生成二维码图片,并且将二维码放进一张底层图片上,并赋予文字。
1.首先我们要想办法生成二维码,二维码是黑白双色,中间不用添加商户logo,这里我们采用的google的jar包生成二维码
导入maven依赖:
<dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.3.3</version> </dependency>
用到的是自己写的工具类:
package com.example.demo;/** * Created by 谈政扬 on 2018/6/15. */ import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.InputStream; import java.util.HashMap; import java.util.Map; /** * @author 谈政扬 * @create 2018-06-15 15:55 * @desc **/ public class Qrcode { /** * 黑色 */ private static final int BLACK = 0xFF000000; /** * 白色 */ private static final int WHITE = 0xFFFFFFFF; /** * 二维码的宽 */ private static final int WIDTH = 360; /** * 二维码的高 */ private static final int HEIGHT = 360; /** * 二维码传图片为正方形 * * @param matrix * @return */ public static BufferedImage toBufferedImage(BitMatrix matrix) { int width = matrix.getWidth(); int height = matrix.getHeight(); BufferedImage image = new BufferedImage(width, HEIGHT, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < width; x++) { for (int y = 0; y < HEIGHT; y++) { image.setRGB(x, y,WHITE); } } for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE); } } return image; } /** * 生成二维码,生成的是二维码图片 * @author 谈政扬 * @date 2018/6/13 11:31 * @param [content] * @return java.awt.image.BufferedImage */ @SuppressWarnings("unchecked") public static BufferedImage createQrCode(String content) throws Exception { MultiFormatWriter multiFormatWriter = new MultiFormatWriter(); @SuppressWarnings("rawtypes") Map hints = new HashMap(); // 设置UTF-8, 防止中文乱码 hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 设置二维码四周白色区域的大小 hints.put(EncodeHintType.MARGIN, 1); // 设置二维码的容错性 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 画二维码 BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, hints); BufferedImage image = toBufferedImage(bitMatrix); return image; } /** * 把二维码图片添加到背景图 * * @param barCodeImage * @param logoPic */ public static BufferedImage addLogo_QRCode(BufferedImage erweima, InputStream bgp)throws Exception { //读取二维码图片,并构建绘图对象360*360 //保持二维码是正方形的 int widtherweima = erweima.getWidth(); int heighterweima = erweima.getHeight(); /** * 读取背景图片600*900 */ BufferedImage bgpi = ImageIO.read(bgp); int widthbgpi = bgpi.getWidth(); int heightbgpi = bgpi.getHeight(); // 计算图片放置位置 int x = 120; int y = 236; //构建背景的图片 Graphics2D bgpiGraphics = bgpi.createGraphics(); bgpiGraphics.drawImage(erweima, x, y, widtherweima, heighterweima, null); bgpiGraphics.dispose(); return bgpi; } /** * 将文字写入背景图片中, 生成的图片以流的行式返回 * * @param qrcFile 路径 * @param qrCodeContent 二维码内容 * @param pressText 增加的文字 * @throws Exception */ public static BufferedImage generateQrCode(BufferedImage image, String qrCodeContent, String pressText) throws Exception { Graphics g = image.getGraphics(); ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); //设置字体,下面商户名称 Font font=new Font("宋体", Font.PLAIN, 40); g.setFont(font); g.setColor(Color.white); FontMetrics metrics = g.getFontMetrics(font); // 文字在图片中的坐标 这里设置在中间 int startX = (600 - metrics.stringWidth(pressText)) / 2; int startY=650; g.drawString(pressText, startX, startY); g.dispose(); return image; } }
在接口中调用方法启动:
@GetMapping(value = "/QrcodeDown/{mchId}") public void QrcodeDown(@PathVariable("mchId")String mchId, HttpServletResponse response){ Map resultMap = new HashMap<String,Object>(5); try { //二维码内容,这里的路径根据自己的业务需求填写 String qrCodeContent="http://www.baidu.com"+"&mch="+mchId; //商户名称 // Map<String, Object> map1 = paymentService.selectmchInfoByMchId(mchId); //String name = map1.get("name").toString(); String name ="**科技"; //springboot读取文件为流对象 InputStream stream = getClass().getClassLoader().getResourceAsStream("img/original.jpg"); //生成二维码 BufferedImage erweima = Qrcode.createQrCode(qrCodeContent); //将二维码放在背景图上 BufferedImage image = Qrcode.addLogo_QRCode(erweima, stream); //给图片添加文字并且输出 BufferedImage bufferedImage = Qrcode.generateQrCode(image, qrCodeContent, name); name=name+".jpg"; response.setHeader("content-disposition", "attachment;filename=" + new String(name.getBytes("utf-8") , "ISO_8859_1")); response.setContentType("application/octet-stream"); ServletOutputStream sos = response.getOutputStream(); ImageIO.write(bufferedImage,"jpg",sos); sos.close(); }catch (Exception e){ e.printStackTrace(); resultMap.put("msg","服务器异常"); } }
在最后提醒大家一句:
因为公司主要用springboot框架进行开发,在读取背景图片时不能以文件行式读取,只能以流的行式读取。不然在linux下部署项目时不能读取到文件,会一直报file is not found错。我在这里就耽误了很多时间,一直认为是自己的路径没找到,没成想是不能以文件行式读取,最好以输入流的行式读取。最后还有一个问题就是,在linux系统下并没有宋体的字体库,所以还得去下载宋体字体库,不然添加的文字显示时是乱码。
效果图: