Bootstrap

Java Graphics2D的使用

Java Graphics2D的使用

前言

​ 最近实习任务要转换一个绘图相关的.net程序,大概是这样

image-20210303113532040

一开始挺怕的毕竟没弄过图形相关的,之前学习Java的时候碰到也说无脑跳过,大概一周多一点时间我大概解决了这个任务,虽然这个程序难点主要是坐标/比例尺转化未平面绘图坐标,但我觉得学到的Graphics2D相关经验也说非常宝贵的,记录下相关方法,下图是我完成后的

image-20210303114057683

一、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获取图片路径,具体流程是这样

  1. 读取配置文件,获得图片路径

  2. 根据图片路径获取图片的BufferedImage对象

  3. 使用获取的图片对象创建TexturePaint填充笔

  4. 使用获取的填充笔对象设置到graphics2D对象里

  5. 使用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)

;