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);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM