海报生成的Java方法

preface

以下是我在实际工作的项目中,想要实现从后端生成海报的功能,本来项目使用golang开发的,但是对于golang的画图不是很熟悉,所以想到使用Java,但是对于Java的画图其实也不熟悉,但是通过在网上找资料,也算是实现了,本文介绍一下如何实现的步骤

说明

用来处理图像压缩的好用工具
thumbnailator
处理生成二维码的工具
zxing

pom依赖

 <dependency>
            <groupId>net.coobird</groupId>
            <artifactId>thumbnailator</artifactId>
            <version>0.4.14</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <!--打包的时候可以不用包进去,别的设施会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。
                相当于compile,但是打包阶段做了exclude操作-->
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.4.1</version>
        </dependency>
       

以下是主要代码

code

工具方法


    public static BufferedImage generate(int type, String msgTitle, String link) throws Exception {
        BufferedImage bimg = null;
        try {
            bimg = ImageIO.read(Objects.requireNonNull(UltimateImgGenerator.class.getClassLoader().getResourceAsStream("img.png")));
            System.out.println(bimg.getHeight());
            System.out.println(bimg.getWidth());
        } catch (IOException e1) {

            e1.printStackTrace();

        }
        Graphics2D g2d = (Graphics2D) bimg.getGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        g2d.setColor(Color.red);
        //矩形区域颜色
        Msg[] msgs = {
                new Msg(new Color(0, 95, 249), "事件提醒", 1),
                new Msg(new Color(252, 193, 32), "天气预报", 2),
                new Msg(new Color(43, 197, 154), "星座运势", 3),
                new Msg(new Color(249, 94, 100), "灾害预警", 4),
                new Msg(new Color(102, 80, 252), "消息推送", 5),
        };
        Msg msg = msgs[type - 1];
        //设置圆角矩形的颜色
        Color color = msg.color;
        g2d.setColor(color);

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);


        //画圆角曲形
        int width = 20/*左边距离*/ + msg.title.length() * 30/*字体总宽度,每个字30*/ + 20/*右边距离*/;
        g2d.fillRoundRect(60, 366, width, 54, 6, 6);//涂一个圆角矩形块
        
        Font font = new Font("Source Han Sans CN Bold", 0, 30);
        g2d.setFont(font);
        FontMetrics metrics = g2d.getFontMetrics(font);

        //为了使标题能够在所画的矩形区域中居中显示 开始
        // 字符打印实际需要的宽度,可能小于矩形的宽,也可能大于矩形的宽
        int stringWidth = metrics.stringWidth(msg.title);
        int rectWidth = 20 * 2 + stringWidth;
        int rectX = 60;
        int rectY = 366;
        int rectHeight = 54;
        // 字符打印的x坐标 = 矩形的起点坐标 + 字符居中打印情况下字符的边与矩形边的距离(可能是正,也可能是负数)
        int x = rectX + (rectWidth - stringWidth) / 2;
        // 字符打印的y坐标(基线的y坐标)= 矩形的起点y坐标 + 字符居中打印下字符的上面与矩形上面距离 + 字符上面到基线的距离
        int y = rectY + (rectHeight - metrics.getHeight()) / 2 + metrics.getAscent();

        //        矩形区域中字体的颜色
        color = new Color(255, 255, 255);
        g2d.setColor(color);
        g2d.drawString(msg.title, x, y);
        //为了使标题能够在所画的矩形区域中居中显示 结束

        g2d.setColor(Color.black);
        font = new Font("Source Han Sans CN Bold", 0, 102);

        g2d.setFont(font);


        g2d.setStroke(new BasicStroke(15));

        metrics = FontDesignMetrics.getMetrics(font);
        int currentWidth = 0;
        int lineNum = 0;
        int i = 0;
        StringBuilder currentLineStr = new StringBuilder();
        //为了使每一行的字符长度不超过规定的长度
        do {
            if (i > msgTitle.length() - 1) {
                //跳出之前检查是否花完毕,如果有,则画完再退出

                if (currentLineStr.length() > 0) {
                    g2d.drawString(currentLineStr.toString(), 60, 620 + 122 * lineNum);
                }
                break;
            }
            char c = msgTitle.charAt(i);
            //            log.info("c:{}",c);
            currentWidth += metrics.charWidth(c);
            currentLineStr.append(c);
            boolean flag = false;
            if (lineNum == 2) {
                //如果是最后一行,尝试着每次都增加一个省略号,如果加上省略号已经大于840,那么就剪去最后一个字符然后写入并退出
                if (currentWidth + 75 > 840) {
                    currentLineStr.deleteCharAt(currentLineStr.length() - 1);
                    //     汉字:[0x4e00,0x9fa5] 或  十进制[19968,40869]
                    //     数字:[0x30,0x39] 或   十进制[48, 57]
                    //     小写字母:[0x61,0x7a] 或  十进制[97, 122]
                    //     大写字母:[0x41,0x5a] 或  十进制[65, 90]
                    //此处使为了不让最后一个字符使特殊字符
                    char last = currentLineStr.charAt(currentLineStr.length() - 1);
                    //如果所有文字的最后一个字符绝对不能是特殊字符,则用while
                    while (!(last >= 48 && last <= 57 || (last >= 65 && last <= 90) || (last >= 97 && last <= 122) || (last >= 19968 && last <= 40869))) {
                        if (currentLineStr.length() >= 1) {
                            currentLineStr.deleteCharAt(currentLineStr.length() - 1);
                            if (currentLineStr.length() >= 1) {
                                last = currentLineStr.charAt(currentLineStr.length() - 1);
                            }
                        } else {
                            break;
                        }
                    }
                    //如果所有文字的只处理一次最后一个字符绝对不能是特殊字符,则用if

                    //                    if (!(last >= 48 && last <= 57 || (last >= 65 && last <= 90) || (last >= 97 && last <= 122) || (last >= 19968 && last <= 40869))) {
                    //                        if (currentLineStr.length() >= 1) {
                    //                            currentLineStr.deleteCharAt(currentLineStr.length() - 1);
                    //                            if (currentLineStr.length() >= 1) {
                    //                                last = currentLineStr.charAt(currentLineStr.length() - 1);
                    //                            }
                    //                        }
                    //                    }
                    currentLineStr.append("...");
                    g2d.drawString(currentLineStr.toString(), 60, 620 + 122 * lineNum);
                    break;
                }
            }
            if (currentWidth <= 840) {
                //如果当前长度小于840,那么尝试着加上后面一个字符,如果加上之后,大于840,那么此时就应该写入
                if (i + 1 < msgTitle.length() - 1) {
                    int tmpWidth = currentWidth + metrics.charWidth(msgTitle.charAt(i + 1));
                    if (tmpWidth > 840) {
                        flag = true;
                    }
                }
            } else {
                flag = true;
            }
            if (flag) {
                g2d.drawString(currentLineStr.toString(), 60, 620 + 122 * lineNum);
                currentLineStr = new StringBuilder();
                lineNum++;
                currentWidth = 0;
            }
            i++;
        } while (lineNum <= 2);


        QRCodeWriter qrCodeWriter = new QRCodeWriter();

        BitMatrix bitMatrix = qrCodeWriter.encode(link, BarcodeFormat.QR_CODE, 200, 200);
        System.out.println("-------------");
        System.out.println(Arrays.toString(bitMatrix.getBottomRightOnBit()));
        System.out.println(Arrays.toString(bitMatrix.getTopLeftOnBit()));
        System.out.println("-------------");

        //        Path path = FileSystems.getDefault().getPath(filePath);

        //        MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
        BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);


        //此处动态的获取了二维码在图片中的真实的位置,然后把它剪切下来,
        // 然后按照需要的尺寸进行了缩放,缩放之后才把这个缩放得到的图片粘贴到了大的图片上
        BufferedImage simage = bufferedImage.getSubimage(bitMatrix.getTopLeftOnBit()[0], bitMatrix.getTopLeftOnBit()[1], bitMatrix.getBottomRightOnBit()[0] - bitMatrix.getTopLeftOnBit()[0], bitMatrix.getBottomRightOnBit()[1] - bitMatrix.getTopLeftOnBit()[1]);
        //缩放图片
        BufferedImage image = new BufferedImage(126, 126, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = image.createGraphics();
        Image img = simage.getScaledInstance(126, 126, Image.SCALE_DEFAULT);
        graphics.drawImage(img, 0, 0, null);
        //        //一定要释放资源
        //        graphics.dispose();
        g2d.drawImage(image, null, 774, 1100);

        return bimg;
    }

代码调用

使用的是springboot框架,在controller里面调用


    @RequestMapping(value = "/generate2", produces = MediaType.IMAGE_PNG_VALUE)
    @ResponseBody
    public byte[] generate2
            (@RequestParam(name = "type") int type,
             @RequestParam(name = "link") String link,
             @RequestParam(name = "msg") String title,
             @RequestParam(name = "id") String id) {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        String[] fontFamilies = ge.getAvailableFontFamilyNames();
        for (String s : fontFamilies) {
            log.info("字体:{}",s);
        }


        if (type < 1 || type > 5) {
            return new Result(500, "type只能是1-5的数字", null).toString().getBytes(StandardCharsets.UTF_8);
        }
        log.info("type:{},link:{},msg:{},id:{}", type, link, title, id);
        Pattern pattern = Pattern.compile("^[0-9a-zA-Z-$]{6,32}$");
        Matcher matcher = pattern.matcher(id);
        if (!matcher.matches()) {
            return new Result(501, "id只能是6-32位的(数字、字母、中横线、$)的组合", null).toString().getBytes(StandardCharsets.UTF_8);
        }
        try {
            BufferedImage bimg = UltimateImgGenerator.generate(type, title, link);
            return bufferedImageToByteArray(bimg);
        } catch (Exception e) {
            return new Result(502, "生成图片异常", null).toString().getBytes(StandardCharsets.UTF_8);

        }
    }


    public static InputStream bufferedImageToInputStream(BufferedImage image) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "png", os);
            InputStream input = new ByteArrayInputStream(os.toByteArray());
            return input;
        } catch (IOException e) {
            log.error("提示:", e);
        }
        return null;
    }

    public static byte[] bufferedImageToByteArray(BufferedImage image) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "png", os);
            return os.toByteArray();
        } catch (IOException e) {
            log.error("提示:", e);
        }
        return null;
    }

效果

启动本地服务地址https://localhost:8080/generate2?id=wuElsjkd&type=5&msg=聚合云推是用来帮助用户完成日常事件提醒的工具&link=http://tui.juhe.cn
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您可以使用以下代码来生成二维码海报: ```java import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; import com.google.zxing.BarcodeFormat; import com.google.zxing.common.BitMatrix;import com.google.zxing.qrcode.QRCodeWriter; public class QRCodeGenerator { public static void main(String[] args) { String qrCodeText = "https://www.example.com"; // 二维码包含的文本信息 String filePath = "qr_code.png"; // 生成的二维码图片保存的文件路径 int size = 300; // 二维码图片的大小 try { // 创建QRCodeWriter对象 QRCodeWriter qrCodeWriter = new QRCodeWriter(); // 创建BitMatrix对象,表示二维码的矩阵 BitMatrix bitMatrix = qrCodeWriter.encode(qrCodeText, BarcodeFormat.QR_CODE, size, size); // 创建BufferedImage对象,表示二维码图片 BufferedImage bufferedImage = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB); bufferedImage.createGraphics(); // 设置二维码图片的背景颜色和前景颜色 Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics(); graphics.setColor(Color.WHITE); graphics.fillRect(0, 0, size, size); graphics.setColor(Color.BLACK); // 绘制二维码图片 for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (bitMatrix.get(i, j)) { graphics.fillRect(i, j, 1, 1); } } } // 保存二维码图片到文件 ImageIO.write(bufferedImage, "png", new File(filePath)); System.out.println("二维码海报生成并保存到文件:" + filePath); } catch (Exception e) { System.out.println("生成二维码海报时出现错误:" + e.getMessage()); } } } ``` 这段代码使用了 Google 的 ZXing 库来生成二维码。您需要在代码中设置二维码包含的文本信息、生成的二维码图片保存的文件路径以及二维码图片的大小。然后,该代码将会生成一个黑白的二维码海报,并保存到指定的文件路径中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

micro_cloud_fly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值