《Java数字图像处理:编程技巧与应用实践》——1.4 Swing Java 2D的其他高级特性介绍

简介:

本节书摘来自华章计算机《Java数字图像处理:编程技巧与应用实践》一书中的第1章,第1.4节,作者 贾志刚,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

1.4 Swing Java 2D的其他高级特性介绍

1 . Stroke接口

Stroke是Graphics2D的API接口,用来实现图形的描边修饰,在Java 2D中只有一个完成Stroke接口的类BasicStroke,如果有需要,可以自己完成Stroke接口,实现自定义的Stroke类。如何使用Stroke的实现类?方法如下:

1)调用Graphics2D 的setStroke()方法,传入一个实例化的Stroke对象。
2)调用draw()方法,传入要绘制的几何形状。

BasicStroke的对象构造函数代码如下:

// 创建Stroke对象实例
float[] dash = {10.0f, 5.0f, 3.0f};
Stroke dashed = new BasicStroke(2.0f, BasicStroke.CAP_BUTT,
    BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f);

其中:

  • 第一个参数2.0f表示Stroke的宽度。
  • 第二个参数声明Stoke的结束方式,BasicStroke.CAP_BUTT表示如果不是闭合区域则不做任何修饰,直接结束绘制,BasicStroke.CAP_ROUND表示如果不是闭合则添加圆角帽线,然后结束。
  • 第三个参数表示线的连接方式,此处为JOIN_MITER。
  • 第四个参数指定Stoke线段的长度,此处线段长度为10。
  • 第五个参数声明点线模式,此处点线模式dash为不等长线段。
  • 第六个参数声明位移,0.0表示位移间隔为零。

更详细的参数说明可以参考JDK的官方文档,下面的代码通过创建BasicStroke实例对象来绘制一个虚线矩形:

// 创建Stroke对象实例
float[] dash = {10.0f, 5.0f, 3.0f};
Stroke dashed = new BasicStroke(2.0f, BasicStroke.CAP_SQUARE,
            BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f);
    
// 设置Graphics2D的Stroke对象引用
g2.setStroke(dashed);
    
// 创建形状
Shape rect2D = new RoundRectangle2D.Double(50, 50, 
                    300, 100, 10, 10);
g2.draw(rect2D);

2 . Texture Fill接口

Texture Fill即纹理填充,Graphics2D提供了setPaint()方法来设置纹理填充,通过fill()方法可实现对几何形状的填充。前面讲到的两种填充方式分别为颜色填充与渐变填充,这里将重点介绍纹理填充的类TexturePaint创建与使用。

TexturePaint通过构造一个BufferedImage对象作为纹理来填充几何形状,因为Buffered-Image对象数据将被拷贝到TexturePaint中,所以BufferedImage对象设置得比较小为好。实例化一个TexturePaint对象的代码如下:

Rectangle2D rect = new Rectangle2D.Double(10,10,200,200);
TexturePaint tp = new TexturePaint(image, rect)

其中image表示一个BufferedImage实例,rect表示截取作为纹理的区域。
使用实例化的TexturePaint来完成对矩形区域填充的代码如下:

// Texture Fill
Rectangle2D rect = new Rectangle2D.Double(10,10,200,200);
TexturePaint tp = new TexturePaint(image, rect);
g2.setPaint(tp);
g2.fill(rect2D);

3 . Font属性

Java 2D支持绝大多数常见字体的创建与属性值的修改调整,可通过Graphics2D setFont()方法来实现绘制字体的修改,同时Graphics2D绘制引擎还支持自定义的外部字体文件*.ttf的动态加载与使用。只要在使用之前加载字体文件即可,使用下面的代码可实现字体文件加载:

public Font loadFont() throws FontFormatException, IOException 
{
    String fontFileName = "AMERSN.ttf";
    InputStream is = this.getClass().
            getResourceAsStream(fontFileName);
    Font actionJson = Font.createFont(Font.TRUETYPE_FONT, is);
    Font actionJsonBase = actionJson.deriveFont(Font.BOLD, 16);
    return actionJsonBase;
}

字体加载与使用的完整代码如下:

package com.book.chapter.one;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.io.IOException;
import java.io.InputStream;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class FontDemo extends JPanel {

private static final long serialVersionUID = 1L;

public FontDemo() {
        super();
}

public void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    // 反锯齿
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
            RenderingHints.VALUE_ANTIALIAS_ON);
    // 设置画笔颜色
    g2d.setPaint(Color.BLUE); 
    try {
        g2d.setFont(loadFont());
    } catch (FontFormatException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    g2d.drawString("Font Demo", 50, 50);
    g2d.dispose(); // 释放资源
}

public Font loadFont() throws FontFormatException, 
IOException {
    String fontFileName = "AMERSN.ttf";
    InputStream is = this.getClass().
        getResourceAsStream(fontFileName);
    Font actionJson = Font.createFont(
            Font.TRUETYPE_FONT, is);
    Font actionJsonBase = 
        actionJson.deriveFont(Font.BOLD, 16);
    return actionJsonBase;
}

public static void main(String[] args) {
    JFrame ui = new JFrame("Font Demo Graphics2D");
    ui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    ui.getContentPane().setLayout(new BorderLayout());
    ui.getContentPane().add(new FontDemo(), 
        BorderLayout.CENTER);
    ui.setPreferredSize(new Dimension(380, 380));
    ui.pack();
        ui.setVisible(true);
    }
}

4 . GeneralPath与自定义几何形状

Java 2D支持通过GeneralPath实现绘制任意的几何形状,使用GeneralPath提供的API接口绘制几何形状的步骤大致如下:

1)实例化GeneralPath对象。
2)调用moveTo()方法锚地开始点坐标。
3)调用lineTo()或curveTo方法绘制连接线。
4)调用closePath()方法完成几何形状绘制。

下面的代码实现了利用GeneralPath对象绘制一个红色五角星图案。

package com.book.chapter.one;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class GeneralPathDemo extends JPanel {
    /**
    * 
    */
    private static final long serialVersionUID = 1L;

    public GeneralPathDemo() {
        super();
    }

    public void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        // 反锯齿
        g2d.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING, 
                RenderingHints.VALUE_ANTIALIAS_ON);

        // 五角星的五个点坐标
        int x1 = this.getWidth() / 2;
        int y1 = 20;
        int x2 = this.getWidth() / 5;
        int y2 = this.getHeight() - 20;
        int x3 = x2 * 4;
        int y3 = this.getHeight() - 20;
        int x4 = 20;
        int y4 = this.getHeight() / 3;
        int x5 = this.getWidth() - 20;
        int y5 = y4;

        // 定义画点的顺序
        int x1Points[] = { x1, x2, x5, x4, x3 };
        int y1Points[] = { y1, y2, y5, y4, y3 };

        // 设置填充颜色
        g2d.setPaint(Color.RED);

        // 实例化GeneralPath对象
        GeneralPath polygon = new GeneralPath(
                GeneralPath.WIND_EVEN_ODD,
                x1Points.length);
        // 锚地开始第一个点
        polygon.moveTo(x1Points[0], y1Points[0]);
        // 顺序画出剩下点
        for (int i = 1; i < x1Points.length; i++) {
            polygon.lineTo(x1Points[i], y1Points[i]);
        }

        // 调用closePath形成一个封闭几何形状
        polygon.closePath();

        // 绘制它
        g2d.draw(polygon);

        // 释放资源
        g2d.dispose();
    }

    public static void main(String[] args) {
        JFrame ui = new JFrame("Demo Graphics");
        ui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ui.getContentPane().setLayout(new BorderLayout());
        ui.getContentPane().add(new GeneralPathDemo(),
                    BorderLayout.CENTER);
        ui.setPreferredSize(new Dimension(380, 380));
        ui.pack();
        ui.setVisible(true);
    }

}
相关文章
|
18天前
|
数据采集 监控 Oracle
GraalVM 24 正式发布阿里巴巴贡献重要特性 —— 支持 Java Agent 插桩
阿里巴巴是 GraalVM 全球顾问委员会的唯一中国代表,阿里云程序语言与编译器团队和可观测团队合作实现了 GraalVM 应用的无侵入可观测能力,并在 ARMS 平台上线了该功能。目前在 GraalVM 24 中发布的是支持 Java agent 的第一步,其余能力将在 GraalVM 的后续版本中陆续发布。
115 21
|
1月前
|
缓存 运维 Java
Java静态代码块深度剖析:机制、特性与最佳实践
在Java中,静态代码块(或称静态初始化块)是指类中定义的一个或多个`static { ... }`结构。其主要功能在于初始化类级别的数据,例如静态变量的初始化或执行仅需运行一次的初始化逻辑。
71 4
|
1月前
|
人工智能 自然语言处理 前端开发
从理论到实践:使用JAVA实现RAG、Agent、微调等六种常见大模型定制策略
大语言模型(LLM)在过去几年中彻底改变了自然语言处理领域,展现了在理解和生成类人文本方面的卓越能力。然而,通用LLM的开箱即用性能并不总能满足特定的业务需求或领域要求。为了将LLM更好地应用于实际场景,开发出了多种LLM定制策略。本文将深入探讨RAG(Retrieval Augmented Generation)、Agent、微调(Fine-Tuning)等六种常见的大模型定制策略,并使用JAVA进行demo处理,以期为AI资深架构师提供实践指导。
277 73
|
1月前
|
Arthas 监控 Java
拥抱 OpenTelemetry:阿里云 Java Agent 演进实践
拥抱 OpenTelemetry:阿里云 Java Agent 演进实践
|
3月前
|
IDE Java API
Java游戏开发基础:从零开始制作一个简单的2D游戏
本文介绍了使用Java开发一个简单的2D避障游戏的基础流程。
134 10
|
3月前
|
Kubernetes Java 持续交付
小团队 CI/CD 实践:无需运维,Java Web应用的自动化部署
本文介绍如何使用GitHub Actions和阿里云Kubernetes(ACK)实现Java Web应用的自动化部署。通过CI/CD流程,开发人员无需手动处理复杂的运维任务,从而提高效率并减少错误。文中详细讲解了Docker与Kubernetes的概念,并演示了从创建Kubernetes集群、配置容器镜像服务到设置GitHub仓库Secrets及编写GitHub Actions工作流的具体步骤。最终实现了代码提交后自动构建、推送镜像并部署到Kubernetes集群的功能。整个过程不仅简化了部署流程,还确保了应用在不同环境中的稳定运行。
143 9
|
4月前
|
存储 IDE Java
漂亮不是梦!Java Swing美化攻略
Java Swing 是一个为 Java 设计的 GUI 工具包,提供文本框、按钮等组件。尽管其外观可定制,通过 Look and Feel(LAF)机制改变应用风格,如 Darcula 和 FlatLaf,但现已淡出主流视野,主要应用于 IDE 领域,如 IntelliJ IDEA 和 Eclipse。相比其他 GUI 框架,Swing 的发展前景有限。
118 1
|
4月前
|
存储 Java 开发者
什么是java的Compact Strings特性,什么情况下使用
Java 9引入了紧凑字符串特性,优化了字符串的内存使用。它通过将字符串从UTF-16字符数组改为字节数组存储,根据内容选择更节省内存的编码方式,通常能节省10%至15%的内存。
|
4月前
|
安全 Java 数据库连接
Java中的异常处理:理解与实践
在Java的世界里,异常处理是维护代码健壮性的守门人。本文将带你深入理解Java的异常机制,通过直观的例子展示如何优雅地处理错误和异常。我们将从基本的try-catch结构出发,探索更复杂的finally块、自定义异常类以及throw关键字的使用。文章旨在通过深入浅出的方式,帮助你构建一个更加稳定和可靠的应用程序。
60 5
|
4月前
|
安全 Java 程序员
Java内存模型的深入理解与实践
本文旨在深入探讨Java内存模型(JMM)的核心概念,包括原子性、可见性和有序性,并通过实例代码分析这些特性在实际编程中的应用。我们将从理论到实践,逐步揭示JMM在多线程编程中的重要性和复杂性,帮助读者构建更加健壮的并发程序。