Java Graphics2D的使用
文章目录
前言
最近实习任务要转换一个绘图相关的.net程序,大概是这样
一开始挺怕的毕竟没弄过图形相关的,之前学习Java的时候碰到也说无脑跳过,大概一周多一点时间我大概解决了这个任务,虽然这个程序难点主要是坐标/比例尺转化未平面绘图坐标,但我觉得学到的Graphics2D相关经验也说非常宝贵的,记录下相关方法,下图是我完成后的
一、Graphics2D基础方法使用
-
创建对象
//创建图片对象 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR); //基于图片对象打开绘图 Graphics2D graphics = image.createGraphics();
-
常用的前置设置(不设置线段/文字不是横竖(就是斜的)的时候会有锯齿)
//消除文字锯齿 g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON); //消除画图锯齿 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-
创建矩形(未绘制)
//声明并创建矩形对象,矩形的左上角是(20,30),宽是300,高是40 Rectangle2D back = new Rectangle2D.Double(20,30,300,40); graphics.fill(back);
-
创建制圆(未绘制)
//声明并创建圆对象,矩形的左上角是(20,30),宽是100,高是100 Ellipse2D.Double ellipse = new Ellipse2D.Double(20, 20, 100, 100); graphics.draw(ellipse);
-
创建线段(未绘制)
// 参数就是两个点的xy坐标 x1,y1,x2,y2 Line2D.Float line = new Line2D.Float(10, 10, 20, 20);
-
绘制 - 基本常用的就是draw(绘制边线) fill(填充:填充内容根据前置设置而定)
// 前置可以进行线条粗细、字体大小、画笔颜色等属性的设置 // 设置画笔颜色 graphics.setColor(Color.WHITE); // 设置画笔粗细 Stroke stroke=new BasicStroke(2.0f);//设置线宽为2.0 graphics.setStroke(stroke); // 设置字体大小 graphics.setFont(new Font("仿宋",Font.BOLD,fontSize)); // 绘制文字 content-内容 xy坐标 // 文字画入画布中 graphics.drawString(content, x,y); // 直接放入图形对象 graphics.draw(图形对象); // 可以写入本地文件(文件名无路径默认/src下) //保存图片 JPG表示保存格式 ImageIO.write(image,"JPEG",new FileOutputStream("a.jpg")); ImageIO.write(image, "png", new File("abcd.png"));
二、绘制不规则多边形
不多说直接上代码
/**
* 绘制多边形
* @param pointList 多边形的坐标集
* @return
* @throws FileNotFoundException
* @throws IOException
*/
public BufferedImage drawPolygon(List<Point> pointList) throws FileNotFoundException, IOException {
//得到图片缓冲区
BufferedImage image = new BufferedImage
//INT精确度达到一定,RGB三原色,宽度512,高度512
(1000,600,BufferedImage.TYPE_INT_RGB);
//得到它的绘制环境(这张图片的笔)
Graphics2D g2 = (Graphics2D) image.getGraphics();
//消除文字锯齿
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
//消除画图锯齿
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//设置画笔白色
g2.setColor(Color.white);
//全图填充白色底图
g2.fillRect(0, 0, image.getWidth(), image.getHeight());
//shape的子类,表示一个形状
GeneralPath gp=new GeneralPath();
// 确定两个点
JsonJZD p1=pointList.remove(0);
JsonJZD p2=pointList.remove(0);
//两个点画第一条直线
gp.append(new
Line2D.Double(p1.getX(),p1.getY(),p2.getX(),p2.getY()),true);
//直线分别与余下的点相连
for(Point point: pointList){
gp.lineTo(point.getX(),point.getY());
}
//闭合图形
gp.closePath();
//设置画笔黑色
g2.setColor(Color.BLACK);
// 填充网格- 填充内容来自图片
image = fillPolygon(image,gp);
//填充图形
g2.draw(gp);
// 翻转图形 - 上下翻转180°
// image = imageMisro(image,UPSIDE_DOWN);
// 释放g2资源
g2.dispose();
// ImageIO.write(image,"JPEG",new FileOutputStream("a.jpg"));//保存图片 JPEG表示保存格式
// ImageIO.write(image, "png", new File("abcd.png"));
return image;
}
三、填充(图片)不规则多边形
可以看到我的需求有需要使用网格填充图形,这种填充图像的,网上找的都是C或者C#的代码,而且使用的是多边形扫描线填充算法简单剖析(Scan-Line Filling),本来也是想写个这个方法,奈何数学忘得差不多+还是想偷懒,就想继续寻找, 终于,找到了使用TexturePaint类填充图像的写法,处于便于修改填充图像的目的,我就通过properties获取图片路径,具体流程是这样
-
读取配置文件,获得图片路径
-
根据图片路径获取图片的BufferedImage对象
-
使用获取的图片对象创建TexturePaint填充笔
-
使用获取的填充笔对象设置到graphics2D对象里
-
使用graphics2D对象的fill方法填充目标不规则多边形
具体代码如下(其中第二个方法是读取配置文件的方法)
BufferedImage对象可以像二一样直接创建,这里选择传参
/** * 填充不规则多边形 - 固定填充 src/main/resources/img/fillImg2.jpg * @param image BufferedImage对象 * @param gp 多边形 * @return * @throws IOException */ private BufferedImage fillPolygon(BufferedImage image, GeneralPath gp) throws IOException { // 0.读取配置文件 String url = getProperties("src/main/resources/fill-Img.properties","fill-img.url"); System.out.println("url:" + url); // 1.得到它的绘制环境(这张图片的笔) Graphics2D g2 = (Graphics2D) image.getGraphics(); // 2.填充网格- 填充内容来自图片 BufferedImage fillImg = ImageIO.read(new File(url)); //要填充图片 // 创建矩形(用来放图片的框) Rectangle2D examp = new Rectangle2D.Double(100,100,50,50); // 把图片填充进矩形(矩形大小就是上面矩形的大小) -》 制作成画笔 TexturePaint tp = new TexturePaint(fillImg,examp); //Rectangle2D是img大小 g2.setPaint(tp);//设置g2的画笔为图片样式的 g2.fill(gp);//gp不规则图形 return image; } /** * 根据key读取value * * @Title: getProperties * @Description: 使用缓冲输入流读取配置文件,然后将其加载,再按需操作 * 绝对路径或相对路径, 如果是相对路径,则从当前项目下的目录开始计算, * 如:当前项目路径/config/config.properties, * 相对路径就是config/config.properties * * @param filePath * @param keyWord * @return * @return String * @throws */ public static String getProperties(String filePath, String keyWord){ Properties prop = new Properties(); String value = null; try { // 通过输入缓冲流进行读取配置文件 InputStream InputStream = new BufferedInputStream(new FileInputStream(new File(filePath))); // 加载输入流 prop.load(InputStream); // 根据关键字获取value值 value = prop.getProperty(keyWord); } catch (Exception e) { e.printStackTrace(); } return value; }
四、翻转图像(上下、左右180°)
/**
* 镜像处理 180°水平和垂直翻转
* type = 0 表示上下翻转,type = 1 表示左右翻转
* @param bufferedimage 需要翻转的BufferedImage对象
* @param type
* @return
*/
public static BufferedImage imageMisro(BufferedImage bufferedimage,int type ) {
try
{
int w = bufferedimage.getWidth();
int h = bufferedimage.getHeight();
int[][] datas = new int[w][h];
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
// getRGB 获取图像中的像素整数值 二进制格式
datas[j][i] = bufferedimage.getRGB(j, i);
}
}
int[][] tmps = new int[w][h];
if (type == 0) {
for (int i = 0, a = h - 1; i < h; i++, a--) {
for (int j = 0; j < w; j++) {
tmps[j][a] = datas[j][i];
}
}
} else if (type == 1) {
for (int i = 0; i < h; i++) {
for (int j = 0, b = w - 1; j < w; j++, b--) {
tmps[b][i] = datas[j][i];
}
}
}
for (int i = 0; i < h; i++){
for (int j = 0; j<w ;j++){
bufferedimage.setRGB(j, i, tmps[j][i]);
}
}
return bufferedimage;
//ImageIO.write(bufferedimage, "jpg", file);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
五、绘制文字,简单封装(其实就是drawString)
/**
* content 需要绘制的文字
* interval 文字两端空余像素
* fontSize 文字大小
* x 绘制起始点x
* y 绘制起始点y
* g2 graphics2D对象
*/
public void drawWord(String content,int fontSize, float x, float y,Graphics2D g2) {
//消除文字锯齿
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
//消除画图锯齿
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.BLACK);
g2.setFont(new Font("仿宋",Font.BOLD,fontSize));
g2.drawString(content, x,y); // 文字画入画布中
}
六、【扩展】读取配置文件方法
这里推荐一个博主记录的比较全面[Java 读取 .properties 配置文件的几种方式](https://www.cnblogs.com/sebastian-tyd/p/7895182.html)