java使用Graphics2D绘图/画图方式

 更新时间:2021年11月15日 11:09:31   作者:滴丶学生卡  
这篇文章主要介绍了java使用Graphics2D绘图/画图方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

一、笔者在开发过程中遇到生成分享海报的需求

需要后端动态生成分享图(最终前端自己实现的,哈哈);记录下过程中遇到的一些问题和解决办法。

二、Graphics2D常用API

首先获取Graphics2D实例

BufferedImage bi = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = bi.createGraphics();
// 开启抗锯齿
RenderingHints renderingHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
// 使用高质量压缩
renderingHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics.setRenderingHints(renderingHints);

1、graphics.drawImage(),往画布添加图片,参数有位置及图片宽高

BufferedImage bgmImage = ImageIO.read(new ByteArrayInputStream(FileUtils.readFileToByteArray(new File("filePath"))));
graphics.drawImage(bgmImage, x, y, width, height, null);

2、graphics.drawString(),往画布上添加文字(自动换行需自己实现)

graphics.setFont(new Font("PingFangSC-Regular", Font.PLAIN, 24));
graphics.setColor(Color.WHITE);
graphics.drawString(title, x, y);

3、graphics.fillRoundRect(),带背景色的圆角矩形(用于给文字画背景色,注意要先画矩形背景,再画文字上去),最后两个参数是设置圆角弧度

// 背景色矩形
graphics.setColor(new Color(254, 68, 82));
graphics.fillRoundRect(x, y, width, height, 4, 4);

三、上才艺

1、刚刚提到的画文字自动换行需要自己实现,这里简单说下实现原理;其实就是根据设置的行宽及要画进去的字符串做一个计算,每个文字的行宽是可以拿到的,这样就能算出每行能展示多少个字,然后就能算出总共分多少行展示,最后循环调用graphics.drawString()方法画上去就好了;下面是换行的核心代码:

   private static int drawStringAutoLineFeed(Graphics g, String strContent, int rowWidth, int x, int y) {
        String[] split = strContent.split("\n");
        int total = 0;
        for (String str : split) {
            int height = drawStringAutoLine(g, str, rowWidth, x, y);
            total += height;
            y += height;
        }
        return total;
    }
 
    /**
     * 根据指定宽度自动换行
     * 
     * @param g
     * @param rowWidth
     * @param strContent
     * @param x
     * @param y
     */
    private static int drawStringAutoLine(Graphics g, String strContent, int rowWidth, int x, int y) {
        // 获取字符串 字符的总宽度
        int strWidth = getStringLength(g, strContent);
        // 获取字符高度
        int strHeight = getStringHeight(g);
        // 字符串总个数
        int rows = 0;
        if (strWidth > rowWidth) {
            int rowStrNum = getRowStrNum(strContent.length(), rowWidth, strWidth);
            rows = getRows(strWidth, rowWidth);
            String temp = "";
            for (int i = 0; i < rows; i++) {
                // 获取各行的String
                if (i == rows - 1) {
                    // 最后一行
                    temp = strContent.substring(i * rowStrNum, strContent.length());
                } else {
                    temp = strContent.substring(i * rowStrNum, i * rowStrNum + rowStrNum);
                }
                if (i > 0) {
                    // 第一行不需要增加字符高度,以后的每一行在换行的时候都需要增加字符高度
                    y = y + strHeight;
                }
                g.drawString(temp, x, y);
            }
        } else {
            // 直接绘制
            g.drawString(strContent, x, y);
        }
        return strHeight * rows;
    }
 
    private static int getDrawStringAutoLineHeight(Graphics g, String strContent, int rowWidth) {
        String[] split = strContent.split("\n");
        int height = 0;
        for (String str : split) {
            // 获取字符串 字符的总宽度
            int strWidth = getStringLength(g, str);
            // 获取字符高度
            height += getStringHeight(g) * getRows(strWidth, rowWidth);
        }
        return height;
    }
 
    private static int getStringLength(Graphics g, String str) {
        char[] strChar = str.toCharArray();
        return g.getFontMetrics().charsWidth(strChar, 0, str.length());
    }
 
    // 每一行字符的个数
    private static int getRowStrNum(int strNum, int rowWidth, int strWidth) {
        int rowsNum = 0;
        rowsNum = (rowWidth * strNum) / strWidth;
        return rowsNum;
    }
 
    // 字符行数
    private static int getRows(int strWidth, int rowWidth) {
        int rows = 0;
        if (strWidth % rowWidth > 0) {
            rows = strWidth / rowWidth + 1;
        } else {
            rows = strWidth / rowWidth;
        }
        return rows;
    }
 
    // 字符高度
    private static int getStringHeight(Graphics g) {
        return g.getFontMetrics().getHeight();
    }

使用方法:

graphics.setFont(new Font("PingFangSC-Regular", Font.PLAIN, 12));
graphics.setColor(Color.GRAY);
drawStringAutoLineFeed(graphics, strContent, rowWidth, x, y);

四、输出图片

1、输出图片字节数组

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(bi, "jpg", outputStream);
return outputStream.toByteArray();

2、直接输出图片文件

ImageIO.write(bi, "jpg", new File("outFilePath"));

五、总结

1、简单的并且图片是固定尺寸和样式的场景还比较好使

2、调试过程非常的恶心,不断生成图片看效果

3、样式较为负责的推荐让前端html2image,笔者的前端同事已经实现,效果比后端画图好很多!

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java新手入门学习之正则表达式

    Java新手入门学习之正则表达式

    这篇文章主要给大家介绍了关于Java新手入门学习之正则表达式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • JAVA简单链接Oracle数据库 注册和登陆功能的实现代码

    JAVA简单链接Oracle数据库 注册和登陆功能的实现代码

    这篇文章主要介绍了JAVA链接Oracle并实现注册与登录功能的代码实例,有需要的朋友可以参考一下
    2014-01-01
  • IntelliJ IDEA 2021.1 首个 Beta 版本发布

    IntelliJ IDEA 2021.1 首个 Beta 版本发布

    这篇文章主要介绍了IntelliJ IDEA 2021.1 首个 Beta 版本发布,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • Spring注解实现循环重试功能(适用场景分析)

    Spring注解实现循环重试功能(适用场景分析)

    这篇文章主要介绍了Spring注解实现循环重试功能,本篇主要简单介绍了Springboot中的Retryable的使用,主要的适用场景和注意事项,当需要重试的时候还是很有用的,需要的朋友可以参考下
    2023-04-04
  • SpringBoot实现简易支付宝网页支付功能

    SpringBoot实现简易支付宝网页支付功能

    小编最近实现一个功能基于springboot程序的支付宝支付demo,非常不错适合初学者入门学习使用,今天把SpringBoot实现简易支付宝网页支付功能的示例代码分享给大家,感兴趣的朋友参考下吧
    2021-10-10
  • SpringBoot基于数据库实现定时任务过程解析

    SpringBoot基于数据库实现定时任务过程解析

    这篇文章主要介绍了SpringBoot基于数据库实现定时任务过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • 深入理解什么是Mybatis懒加载(延迟加载)

    深入理解什么是Mybatis懒加载(延迟加载)

    这篇文章主要介绍了深入理解什么是Mybatis懒加载(延迟加载),mybatis的懒加载,也称为延迟加载,是指在进行关联查询的时候,按照设置延迟规则推迟对关联对象的select查询,延迟加载可以有效的减少数据库压力,需要的朋友可以参考下
    2023-10-10
  • java 中Buffer源码的分析

    java 中Buffer源码的分析

    这篇文章主要介绍了java 中Buffer源码的分析的相关资料,需要的朋友可以参考下
    2017-06-06
  • Java并发编程(CyclicBarrier)实例详解

    Java并发编程(CyclicBarrier)实例详解

    这篇文章主要介绍了Java并发编程(CyclicBarrier)实例详解的相关资料,JAVA编写并发程序的时候,我们需要仔细去思考一下并发流程的控制,如何让各个线程之间协作完成某项工作。
    2017-07-07
  • idea中使用Inputstream流导致中文乱码解决方法

    idea中使用Inputstream流导致中文乱码解决方法

    很多朋友遇到一个措手不及的问题当idea中使用Inputstream流导致中文乱码及Java FileInputStream读中文乱码问题,针对这两个问题很多朋友不知道该如何解决,下面小编把解决方案分享给大家供大家参考
    2021-05-05

最新评论