Spring Boot项目使用Graphics2D 生成二维码海报图片流返回给前端

前言

需求是生成二维码分享海报,作为学生加入班级的一个方式,本来想着用前端canvas来实现,生成想要的图片,可视化比较好。后来改为后端生成固定格式的海报图片,只是班级信息发生改变。就想着由前端传入响应的参数,后端根据参数使用Graphics2D 画一张海报,然后通过图片流的方式返回给前端。

生成图片最后效果(省略公司logo)

图片大小是750*1334的

代码

ctroller层接口方法:

@RequestMapping(value = "/getClassQr")
    public void getClassQr(@RequestBody Map<String, String> request, HttpServletResponse response) {
        try {
            // 设置响应流信息
            response.setContentType("image/jpg");
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            //海报的宽高
            int pic_width = 750;
            int pic_height = 1334;
            BufferedImage bufferedImage = new BufferedImage(pic_width, pic_height, BufferedImage.TYPE_INT_RGB);
            OutputStream stream = response.getOutputStream();
            bufferedImage = getClassQr(request, bufferedImage);
            //以流的形式输出到前端
            ImageIO.write(bufferedImage, "jpg", stream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

核心方法:

    public BufferedImage getClassQr(Map<String, String> request, BufferedImage bufferedImage) {
        String className = request.get("className");
        String kdgtName = request.get("schoolName");
        String note = "扫码加入班级群";
        String url = request.get("url");
        BitMatrix bitMatrix = null;
        Graphics2D graphics2D = (Graphics2D) bufferedImage.getGraphics();
        graphics2D.setColor(Color.WHITE);
        graphics2D.fillRect(0, 0, 750, 1334);
        graphics2D.setColor(Color.BLACK);
        int classNameHeight = 238;
        try {
            Font font = new Font("微软雅黑", Font.BOLD, 48);
            graphics2D.setFont(font);
            graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            //1.填充院系名称
            FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
            graphics2D = makeLineFeed(kdgtName, metrics, 150, 750, graphics2D);
            if (metrics.stringWidth(kdgtName) > 750) {
                classNameHeight = 150 + metrics.getHeight() * 2;
            }
            //2.填充班级名称
            font = new Font("微软雅黑", Font.PLAIN, 32);
            graphics2D.setFont(font);
            int height = metrics.getHeight();
            metrics = FontDesignMetrics.getMetrics(font);
            //超过图片则换行
            graphics2D = makeLineFeed(className, metrics, classNameHeight, 750, graphics2D);
            //3.填充二维码
            //其他参数,如字符集编码
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            //容错级别为H
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            //白边的宽度,可取0~4
            hints.put(EncodeHintType.MARGIN, 0);
            //生成矩阵,参数URL
            bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 600, 600, hints);
            graphics2D.drawImage(toBufferedImage(bitMatrix), 76, 364, 600, 600, null);
            //4.填充扫码加入班级群字
            font = new Font("微软雅黑", Font.PLAIN, 36);
            graphics2D.setFont(font);
            graphics2D.drawString(note, 252, 1024);
            //5.填充logo图片
//            ClassLoader classLoader = this.getClass().getClassLoader();
//            String path = classLoader.getResource("").getPath().replace("/WEB-INF/classes/", "/resources/images/oasisbasic/logo.png");
//            InputStream inputStream = classLoader.getResourceAsStream(path);
//            graphics2D.drawImage(ImageIO.read(inputStream), 206, 1238, 344, 32, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bufferedImage;
    }

文字超出换行居中方法:

//换行并居中
    public Graphics2D makeLineFeed(String text, FontDesignMetrics metrics, int y, int max_width, Graphics2D graphics2D) {
        int stringlenth = metrics.stringWidth(text);
        StringBuilder sb = new StringBuilder();
        int x = 25;//边距
        // 判断字符长度是否大于图片宽度
        if (stringlenth > max_width) {
            int line_width = x;
            for (int i = 0; i < text.length(); i++) {
                char c = text.charAt(i);
                sb.append(c);
                // FontDesignMetrics 的 charWidth() 方法可以计算字符的宽度
                int char_width = metrics.charWidth(c);
                line_width += char_width;

                // 如果当前字符的宽度加上之前字符串的已有宽度超出了海报的最大宽度,则换行
                if (line_width >= max_width - 50) {
                    line_width = 0;
                    graphics2D.drawString(sb.toString(), x, y);
                    sb = new StringBuilder();
                }
            }
            //设置第二行居中
            x = (max_width - metrics.stringWidth(sb.toString())) / 2;
            graphics2D.drawString(sb.toString(), x, y + metrics.getHeight());
        } else {
            x = (max_width - metrics.stringWidth(text)) / 2;
            graphics2D.drawString(text, x, y);
        }
        return graphics2D;
    }

将二维码转换成图片方法:

 private 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, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }

请求参数: ulr:localhost:8088/getClassQr

{
	"url":"www.baidu.com",
	"className":"计算机应用技术二班",
	"schoolName":"成都理工大学信息科学与技术学院数字媒体系"
}

开发中遇到的坑

1.通过Postman能够获取出海报图片,但是前端获取是获取不到

	解决办法:将post请求换成request请求,去掉@RequestBody注解,具体原因不太了解,如果有知道的同学欢迎评论区指教,谢谢啦!
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值