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