java绘图(基于Graphics2D)

1.绘图基本操作

请参考下面基础示例:

 1         int width = 200, height = 250;
 2         //创建图片对象
 3         BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
 4         //基于图片对象打开绘图
 5         Graphics2D graphics = image.createGraphics();
 6         //绘图逻辑 START (基于业务逻辑进行绘图处理)……
 7 
 8         //绘制圆形
 9         graphics.setColor(Color.BLACK);
10         Ellipse2D.Double ellipse = new Ellipse2D.Double(20, 20, 100, 100);
11         graphics.draw(ellipse);
12 
13         // 绘图逻辑 END
14         //处理绘图
15         graphics.dispose();
16         //将绘制好的图片写入到图片
17         ImageIO.write(image, "png", new File("abc.png"));

如上代码所示,使用java绘图基本操作流程如下:

  a.得到一个 BufferedImage ,可以是直接指定分辨率new一个空图片,也

  b.基于此BufferedImage 创建一个绘图对象,使用 createGraphics 方法,得 Graphics2D 实例

  c.使用Graphics2D 实例进行画图,所有绘图坐标基于创建此Graphics2D 的BufferedImage。示例中在图片上画了一个圆形。

  d.调用Graphics2D 对象的 dispose() 方法,进行绘图处理,使绘图效果应用到BufferedImage 对象

  e.使用ImageIO类的write函数将图片对象转换到文件或二进制流

 

上面是使用java进行绘图的基本流程,其中步骤c涉及到很多绘图细节。下面总结一些常用绘图操作:

 

限制绘图区域

如果绘图时,只希望指定范围内的区域绘图生效,其他区域不受影响,我们可以使用 setClip 函数Shape区域对象作为参数设置剪辑区域

            Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, diameter, diameter);
            Graphics2D graphics = formatAvatarImage.createGraphics();
            //设置剪辑区域,范围外的区域不受绘图影响。这里指定圆形区域作为绘制区域
            graphics.setClip(shape);
            // 将另一张图片绘制到图像中,
            graphics.drawImage(avatarImage, (diameter - width + circleW) / 2, (diameter - height + circleW) / 2, null);
            graphics.dispose();

 

 

图形的原点坐标:

 由于绘制图形时,所有绘制都基于坐标进行绘制,所以绘制之前必须了解图形的原点坐标,才能将图形绘制到准确的位置

  1.方形:方形的原点坐标位于左上角(图片本身都是方形,因此在图像中绘制另一张图片时,图片的原点坐标也在左上角)

  2.椭圆形: 椭圆形的原点坐标位于圆心

  3.文字:文字的原点坐标位于左侧与基线的交点上(参考后面绘制文字)

 

绘制图片

  图片绘制主要分三步

  1.将图片转换为BufferedImage 对象

  2.计算绘制位置

  3.进行绘制

1         //将图片转换为BufferedImage对象
2         BufferedImage bufferedImage = ImageIO.read(new File("C:\\Users\\minggliu\\Pictures\\test\\test.png"));
3         //计算绘制位置
4         int x = 0, y = 0;
5         //执行绘制
6         //graphics.drawImage(bufferedImage.getScaledInstance(imageW, imageH, Image.SCALE_DEFAULT),100, 100, null);
7         //graphics.drawImage(bufferedImage, 0, 0, width / 2, height / 2, null);
8         graphics.drawImage(bufferedImage, x, y, null);

注意到上面执行绘制注释了上面两种,

 a.使用

graphics.drawImage(bufferedImage, x, y, null);
绘制图片不会进行resize

b.使用
graphics.drawImage(bufferedImage, 0, 0, width / 2, height / 2, null);
绘制图片,系统会将图片resize到 width / 2, height / 2 大小

c.使用
graphics.drawImage(bufferedImage.getScaledInstance(imageW, imageH, Image.SCALE_DEFAULT),100, 100, null);

 绘制图片则先进行了resize,再画到对应的位置,结果与b相同,不过预先的resize有更多的功能,可以指定resize方式

 

对于一些特殊resize要求,需要走代码逻辑进行特殊处理,下面给出常用resize方式:

以图形中间为原点进行无压缩裁剪resize:

    public static BufferedImage resize(BufferedImage image, int needW, int needH) {
        int resizeW, resizeH, resizeX, resizeY;
        int imgW = image.getWidth(), imgH = image.getHeight();
        int wantH = imgW * needH / needW;
        //如果图片属于过方形
        if (wantH < imgH) {
            resizeH = imgW * needH / needW;
            resizeW = imgW;
            resizeX = 0;
            resizeY = (imgH - wantH) / 2;
        }
        //图片属于过长形
        else {
            resizeH = imgH;
            resizeW = imgH * needW / needH;
            resizeX = (imgW - imgH * needW / needH) / 2;
            resizeY = 0;
        }
        return image.getSubimage(resizeX, resizeY, resizeW, resizeH);
    }

 

 

绘制文字

1.绘制文字需要指定字体,同时需要系统运行的系统上安装了对应字体

安装:

 a.将字体文件存放到字体目录

/usr/share/fonts

b.刷新字体信息
sudo mkfontscale  #生成核心字体信息
sudo mkfontdir
sudo fc-cache -fv

c.重启进程

 

3.文本框的坐标定位

  文字的原点坐标不同于一般图形在右上角,如果需要将文字准确的绘制到指定位置,需要了解文字的原点坐标位置。

如下图所示,文本框的原点x坐标位于文本框最左侧,y坐标则位于基线上。基线以上为asent,基线以下为decent.

为什么会有基线这个概念,可能会让人产生疑惑,实际上是有原因的。实际上基线相同的文字,即使字体大小不一样,绘制出来的结果是文本底部对齐的。 因为文字底部还有一部分留白,因此文字底部对齐不是基于底部坐标对齐,而是进行基线对齐。

 

如下图所示,为文字的绘制示例, java提供了api获取文本框的长宽高,asent、decent等,我们需要基于字体Font得到 FontMetrics ,基于FontMetrics 我们就能获取字体高度、asent、decent,结合具体的字符串得到宽度(所以文本绘制实际上不支持换行)。

//指定字体
final Font logoFont = new Font("PingFang SC", Font.BOLD, 50);
FontMetrics metrics = graphics.getFontMetrics(logoFont);

//指定要绘制的字符串
String amount = String.valueOf(coupon.getAmount());

//得到字符串绘制宽度
int logoW = metrics.stringWidth(amount);

//计算绘制原点坐标,
//文本最左边位于x轴logoX int logoX = xStart;

//文本基于
logoH 居中对齐
int logoH = hStart + metrics.getHeight() / 2 - metrics.getDescent(); 

//绘制文本框

graphics.setFont(timeFont);

graphics.setPaint(timeColor);
graphics.drawString(amount, logoX, logoH);

 

posted @ 2019-09-22 16:01  minggliu  阅读(33116)  评论(1编辑  收藏  举报