Java后端生成图片工具类分享

前言

最近小编做了一个需求,根据商品的尺寸信息,生成尺寸表图,可是小编之前没做过这样的需求,第一次做这种需求,好有新鲜感,然后小编请教了度娘,学会了两种生成图片的实现方式。特记录下,以免以后忘记,也供大家参考。

生成图片实现方式

方式一:Graphics

上代码:

import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;

/**
 * 图片生成工具
 *
 * @author 哈哈
 * @date 2022/9/1
 */
public class GenerateImageUtil {

    public static String FONT = "宋体";

    public void generateSizeImage(String cellsValue[][], String path, String desc) {
        // 字体大小
        int fontTitileSize = 15;
        // 横线的行数
        int totalrow = cellsValue.length + 1;
        // 竖线的行数
        int totalcol = 0;
        if (cellsValue[0] != null) {
            totalcol = cellsValue[0].length;
        }
        // 图片宽度
        int imageWidth = 1000;
        // 图片高度
        int imageHeight = 1000;
        // 行高
        int rowHeight = 40;
        // 单元格宽度
        int colWidth = 140;
        // 起始宽度
        int startWidth = (imageWidth - (totalcol * colWidth)) / 2;
        // 起始高度
        int startHeight = (imageHeight - totalrow * rowHeight) / 2;

        BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
        Graphics graphics = image.getGraphics();
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, imageWidth, imageHeight);
        graphics.setColor(new Color(220, 240, 240));

        //画横线
        for (int j = 0; j < totalrow; j++) {
            graphics.setColor(Color.lightGray);
            int x1 = startWidth;
            int x2 = (imageWidth + (totalcol * colWidth)) / 2;
            graphics.drawLine(x1, startHeight + j * rowHeight, x2, startHeight + j * rowHeight);
        }
        //画竖线
        for (int k = 0; k < totalcol + 1; k++) {
            graphics.setColor(Color.lightGray);
            int x = startWidth + k * colWidth;
            graphics.drawLine(x, startHeight, x, startHeight + rowHeight * (totalrow - 1));
        }
        //设置字体
        Font font;
        //写入内容
        for (int n = 0; n < cellsValue.length; n++) {
            for (int l = 0; l < cellsValue[n].length; l++) {
                if (n == 0) {
                    font = new Font(FONT, Font.BOLD, fontTitileSize);
                    graphics.setFont(font);
                    graphics.setColor(Color.BLACK);
                } else if (n > 0 && l > 0) {
                    font = new Font(FONT, Font.PLAIN, fontTitileSize);
                    graphics.setFont(font);
                    graphics.setColor(Color.gray);
                } else {
                    font = new Font(FONT, Font.PLAIN, fontTitileSize);
                    graphics.setFont(font);
                    graphics.setColor(Color.BLACK);
                }
                //向单元格里写内容,水平居中&垂直居中
                FontMetrics fontMetrics = graphics.getFontMetrics(font);
                String content = cellsValue[n][l];
                //获取写入内容的宽度
                int contentWidth = fontMetrics.stringWidth(content);
                //获取字体的高度
                int contentHeight = fontMetrics.getHeight();
                //获取字体的下降值
                int contentDescent = fontMetrics.getDescent();
                //计算x、y坐标
                graphics.drawString(content, startWidth + colWidth * l + (colWidth - contentWidth) / 2, startHeight + rowHeight * (n + 1) - contentHeight / 2 - contentDescent);
            }
        }
        //设置备注
        font = new Font(FONT, Font.BOLD, fontTitileSize);
        graphics.setFont(font);
        graphics.drawString(desc, startWidth, startHeight + (totalrow * rowHeight) - 10);
        // 保存图片
        createImage(image, path);
    }

    /**
     * 将图片保存到指定位置
     *
     * @param image        缓冲文件类
     * @param fileLocation 文件位置
     */
    private void createImage(BufferedImage image, String fileLocation) {
        try {
            ImageIO.write(image, "png", new File(fileLocation));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    
    public static void main(String[] args) {
        GenerateImageUtil cg = new GenerateImageUtil();
        try {
            String[][] tableData2 =
                    {{"Size", "Length", "Sleeve Length", "Bust", "Waist Size", "Hip Size", "Cuff"},
                            {"XS", "44.1", "4.3", "20.5-45.7", "21.3-45.7", "49.6", "9.4-22.4"},
                            {"S", "44.9", "4.5", "22-47.2", "22.8-47.2", "51.2", "9.8-22.8"},
                            {"M", "45.7", "4.7", "23.6-48.8", "24.4-48.8", "52.8", "10.3-23.3"},
                            {"L", "46.5", "5", "26-51.2", "26.8-51.2", "55.1", "10.9-23.9"}};
            cg.generateSizeImage(tableData2, "/Users/Downloads/test.jpg", "*This data was obtained from manually measuring the product, it may be off by 1-2 IN.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

产品想要的效果是:

  1. 图片长1000、宽1000
  2. 表格水平垂直居中
  3. 表格内容水平垂直居中
  4. 表格下方加行备注

效果图:

在这里插入图片描述

优点:

  1. 可以灵活的控制图片的大小
  2. Graphics的drawLine、drawString方法,传参有x、y坐标,控制位置也比较灵活

缺点:

  1. 虽然传参x、y坐标比较灵活,但是计算x、y坐标比较繁琐,调整起来不是很方便,
  2. 调整表格的格式没有CSS灵活,如下图,需要一些计算

在这里插入图片描述

基于以上问题,我又了解了其他可以生成图片的方法,比如FreeMarker

方式二:FreeMarker

FreeMarker主要是将HTML转成图片,控制表格格式就很灵活了,做过前后端不分离项目的同学就很容易上手,但是小编的页面功底属实是负数,能调整的效果有限T_T,请担待。

话不多说,上代码。

步骤:

一、引包

   <!-- html转img -->
   <dependency>
     <groupId>gui.ava</groupId>
     <artifactId>html2image</artifactId>
     <version>2.0.1</version>
   </dependency>
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-freemarker</artifactId>
   </dependency>

二、在resource目录下新建templates目录,新建sizeImageTemplate.ftl文件

在这里插入图片描述

sizeImageTemplate.ftl

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
<table style="border: 1px solid black;text-align:center;border-collapse: collapse;">
    <#list contentMap?keys as key>
        <tr>
            <#list (contentMap[key]) as field>
                <td style="border:1px solid black;height:40px;width: 140px">${field}</td>
            </#list>
        </tr>
    </#list>
</table>
<#list desc?keys as key>
    <#list (desc[key]) as field>
        ${field}
    </#list>
</#list>
</body>
</html>

三、转换类

import freemarker.template.Configuration;
import freemarker.template.TemplateException;
import gui.ava.html.Html2Image;
import gui.ava.html.renderer.ImageRenderer;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * Html转换图片
 *
 * @author :哈哈
 * @date :2022-09-01
 */
public class HtmlConvertImgHelper {

    Configuration configuration;

    /**
     * 初始化
     */
    public HtmlConvertImgHelper() {
        if (configuration == null) {
            configuration = SpringContextHolder.getBean(Configuration.class);
        }
    }

    /**
     * freemarker转Image
     *
     * @param fileName   ftl文件名称,需要在resources/templates目录下
     * @param formatType
     * @return
     * @throws IOException
     */
    public byte[] htmlConvertImg(String fileName, Object map, String formatType) throws IOException, TemplateException {
        String htmlText = FreeMarkerTemplateUtils.processTemplateIntoString(configuration.getTemplate(fileName), map);
        return htmlConvertImg(htmlText, formatType);
    }

    /**
     * 根据HTML内容转Image
     *
     * @param htmText    HTML文本字符串
     * @param formatType 图片类型
     */
    public byte[] htmlConvertImg(String htmText, String formatType) throws IOException {
        //最终返回的byte流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        Html2Image html2Image = Html2Image.fromHtml(htmText);
        ImageRenderer imageRenderer = html2Image.getImageRenderer();
        BufferedImage grayPicture = imageRenderer.getBufferedImage(BufferedImage.TYPE_INT_RGB);

        ImageIO.write(grayPicture, formatType, byteArrayOutputStream);
        return byteArrayOutputStream.toByteArray();
    }
}

四、工具类

import com.google.common.collect.Lists;
import freemarker.template.TemplateException;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 图片生成工具
 *
 * @author 哈哈
 * @date 2022/9/1
 */
public class GenerateImageUtil {

    /**
     * 生成表格
     *
     * @param contentMap 表格内容
     * @param desc 备注
     * @param path 保存路径
     * @throws TemplateException
     * @throws IOException
     */
    public static void createSizeTableImage(Map<String, List<String>> contentMap, String desc, String path) throws TemplateException, IOException {
        Map<String, List<String>> descMap = new HashMap<>();
        List<String> descList = Lists.newArrayList(desc);
        descMap.put("desc", descList);
        Map<String, Map<String, List<String>>> map = new HashMap<>();
        map.put("contentMap", contentMap);
        map.put("desc", descMap);
        byte[] bytes = new HtmlConvertImgHelper().htmlConvertImg("sizeImageTemplate.ftl", map, "jpg");
        OutputStream os = new FileOutputStream(path);
        os.write(bytes, 0, bytes.length);
        os.flush();
        os.close();
    }
}

五、测试类

import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
@Slf4j
public class Test {
    @org.junit.Test
    public void ccc() throws IOException, TemplateException {

        Map<String, List<String>> map1 = new HashMap<>();
        List<String> title1 = Lists.newArrayList("Size", "Length", "Sleeve Length", "Bust", "Waist Size", "Hip Size", "Cuff");
        List<String> title2 = Lists.newArrayList("XS", "44.1", "4.3", "20.5-45.7", "21.3-45.7", "49.6", "9.4-22.4");
        List<String> title3 = Lists.newArrayList("S", "44.9", "4.5", "22-47.2", "22.8-47.2", "51.2", "9.8-22.8");
        List<String> title4 = Lists.newArrayList("M", "45.7", "4.7", "23.6-48.8", "24.4-48.8", "52.8", "10.3-23.3");
        List<String> title5 = Lists.newArrayList("L", "46.5", "5", "26-51.2", "26.8-51.2", "55.1", "10.9-23.9");
        map1.put("title1", title1);
        map1.put("title2", title2);
        map1.put("title3", title3);
        map1.put("title4", title4);
        map1.put("title5", title5);

        GenerateImageUtil.createSizeTableImage(map1, "*This data was obtained from manually measuring the product, it may be off by 1-2 IN.", "/Users/Downloads/test1.jpg");
    }
}

效果图:

在这里插入图片描述

小编尽力了。。。我相信大佬们比我会调整页面效果

总结

以上分享了两种生成图片的方法,使用上第一种比较方便,代码量比较少,就是实现的效果上如果比较复杂的话,调整起来不太方便;第二种虽然代码量看起来比较多吧, 但是调整页面更灵活,类似于写JSP页面一样,通过值传递,在页面遍历生成行和列,然后使用style调整表格的格式,对于实现比较复杂的效果,更方便些,只需确保值传递没问题。

本次分享到此结束,谢谢大家,麻烦点个赞呗,小编谢谢了

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值