有這樣一個需求,在一張圖檔上畫幾條線并儲存,如圖所示:
已知各個點的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屬性詳解
對圖像像素點的處理