如何使用Graphics2D在一張圖片上畫線(包括箭頭)
阿新 • • 發佈:2019-01-01
有這樣一個需求,在一張圖片上畫幾條線並儲存,如圖所示:
已知各個點的x,y座標,座標範圍是[0.000,1],即將橫縱方向分成1000份。
我們可以使用java.awt.Graphics2D的庫來實現。
Graphics2D在Graphics類提供繪製各種基本的幾何圖形的基礎上進行擴充套件,擁有更強大的二維圖形處理能力,提供座標轉換、顏色管理以及文字佈局等更精確的控制。Graphics2D類重要的屬性包含以下幾個
- stroke屬性
控制線條的寬度、筆形樣式、線段連線方式或短劃線圖案 - paint屬性
控制填充效果 - transform屬性
實現常用的圖形平移、縮放和斜切等變換操作 - clip屬性
實現剪裁效果 - composit屬性
設定圖形重疊區域的效果 - color
控制顏色,使用RGB構造 - Graphics2D類的繪圖draw()
擴充了Graphics的許多方法,可以畫線段、矩形、橢圓、圓弧、二次曲線甚至三次曲線等
相關程式碼如下:
import javax.imageio.ImageIO; import java.awt.*; import java.awt.geom.Line2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * @author 94977 * @create 2018/12/22 */ public class JfreeChart { /** * 線寬,這裡預設設定所有線寬都一樣,也可根據需求分別設定 */ private static final float STROKE_WIDTH = 3.0f; /** * 箭頭的高度,單位畫素 */ private static final Integer ARROW_HEIGHT = 40; /** * 箭頭底邊的一半,單位畫素 */ private static final Integer ARROW_LENGTH = 20; public static void main(String[] args) throws IOException { File imgFile = new File("D:\\3.jpg"); File imgFile2 = new File("D:\\11.jpg"); BufferedImage srcimg = ImageIO.read(imgFile); //Graphics2D物件相當於畫筆 Graphics2D g2d = srcimg.createGraphics(); // 獲取圖片寬度 int width = srcimg.getWidth(); // 獲取圖片高度 int height = srcimg.getHeight(); // 設定線的型式 Stroke stroke = new BasicStroke(STROKE_WIDTH, // 線寬 BasicStroke.CAP_SQUARE, // 端點樣式 BasicStroke.JOIN_BEVEL, // 接頭樣式 15.0f, // 拼接限制 null, // 虛線 5.0f); //虛線的設定 g2d.setStroke(stroke); //畫方向線 g2d.setColor(new Color(255, 200, 0)); List<CoordinateDto> list2 = new ArrayList<>(); list2.add(new CoordinateDto(0.450,0.650)); list2.add(new CoordinateDto(0.550,0.300)); getDirectionLine(list2,width,height,g2d); //畫檢測線,需至少兩個點 g2d.setColor(Color.GREEN); List<CoordinateDto> list = new ArrayList<>(); list.add(new CoordinateDto(0.400,0.250)); list.add(new CoordinateDto(0.450,0.500)); list.add(new CoordinateDto(0.600,0.600)); list.add(new CoordinateDto(0.750,0.400)); for(int i = 0 ; i < list.size()-1; i++){ g2d.draw(getLine(list.get(i).getX(),list.get(i).getY(),list.get(i+1).getX(),list.get(i+1).getY(),width,height)); } //g2d.fill3DRect(500,400,100,5,true); //畫一個矩形 //RoundRectangle2D rRect = new RoundRectangle2D.Double(13.0,30.0,100.0,70.0,10.0,10.0); //g2d.draw(rRect); //釋放此圖形的上下文並釋放它所使用的所有系統資源 g2d.dispose(); ImageIO.write(srcimg, "JPG", imgFile2); } private static void getDirectionLine(List<CoordinateDto> list, int width, int height, Graphics2D g2){ CoordinateDto startPoint = list.get(0); CoordinateDto endPoint = list.get(1); int sx = (int)(startPoint.getX()*width); int sy = (int)(startPoint.getY()*height); int ex = (int)(endPoint.getX()*width); int ey = (int)(endPoint.getY()*height); drawAL(sx, sy, ex, ey, g2); } /** * 畫箭頭 */ private static void drawAL(int sx, int sy, int ex, int ey, Graphics2D g2) { double H = ARROW_HEIGHT; // 箭頭高度 double L = ARROW_LENGTH; // 底邊的一半 int x3 = 0; int y3 = 0; int x4 = 0; int y4 = 0; double awrad = Math.atan(L / H); // 箭頭角度 double arraow_len = Math.sqrt(L * L + H * H); // 箭頭的長度 double[] arrXY_1 = rotateVec(ex - sx, ey - sy, awrad, true, arraow_len); double[] arrXY_2 = rotateVec(ex - sx, ey - sy, -awrad, true, arraow_len); double x_3 = ex - arrXY_1[0]; // (x3,y3)是第一端點 double y_3 = ey - arrXY_1[1]; double x_4 = ex - arrXY_2[0]; // (x4,y4)是第二端點 double y_4 = ey - arrXY_2[1]; Double X3 = new Double(x_3); x3 = X3.intValue(); Double Y3 = new Double(y_3); y3 = Y3.intValue(); Double X4 = new Double(x_4); x4 = X4.intValue(); Double Y4 = new Double(y_4); y4 = Y4.intValue(); //起始線 g2.drawLine(sx, sy, ex, ey); //箭頭 g2.drawLine(ex, ey, x3, y3); g2.drawLine(ex, ey, x4, y4); //三角形箭頭 //GeneralPath triangle = new GeneralPath(); //triangle.moveTo(ex, ey); //triangle.lineTo(x3, y3); //triangle.lineTo(); //triangle.closePath(); //實心箭頭 //g2.fill(triangle); //非實心箭頭 //g2.draw(triangle); } // 計算 private static double[] rotateVec(int px, int py, double ang, boolean isChLen, double newLen) { double mathstr[] = new double[2]; // 向量旋轉函式,引數含義分別是x分量、y分量、旋轉角、是否改變長度、新長度 double vx = px * Math.cos(ang) - py * Math.sin(ang); double vy = px * Math.sin(ang) + py * Math.cos(ang); if (isChLen) { double d = Math.sqrt(vx * vx + vy * vy); vx = vx / d * newLen; vy = vy / d * newLen; mathstr[0] = vx; mathstr[1] = vy; } return mathstr; } private static Line2D getLine(double x1 ,double y1,double x2 ,double y2, int width, int height){ return new Line2D.Double(x1*width,y1*height,x2*width,y2*height); } }
public class CoordinateDto {
private double x;
private double y;
//省略getter setter
}
主要使用的是Graphics2D.drawLine()方法,注意這個方法引數裡座標是以畫素為單位,所以程式碼中對此進行了些轉換。
相關連結:
stroke屬性詳解
對影象畫素點的處理