Graphics2D渲染(Rendering with Graphics2D)上

Graphics2D渲染
Rendering with Graphics2D

Graphics2D从java.awt.Graphics中继承而来,对提供的图形、文本和图像提供更高级的处理控制。Java 2D的渲染过程就是通过Graphics2D对象以其状态属性来控制的。

当图形对象渲染时,像线条样式和坐标状态等Grahics2D状态属性就被应用到这些图形对象上。这些和Graphics2D相联系的状态属性的集合构成了Graphics2D上下文(Graphics2D Context)。为了渲染文本、图形、图像等,你需要先创建一个Graphics2D上下文,然后调用Graphics2D的渲染方法像draw或者fill等来渲染。

2.1 接口和类
Interfaces and Classes

下面列出了和Graphics2D上下文协同工作的相关的类和接口,其中包括代表状态属性的类。大部分的类被包含在java.awt包中。

Interface Description

Composite 定义了绘制的区域上新的颜色与原有颜色之混合方式。它现有唯一实现
类为AlphaComposite.
CompositeContext 定义了被包含的优化的混合操作的环境。编程人员用它来实现通用的混合规
则。
Paint 继承于:接口Transparency
为draw或fill操作定义颜色。其实现类有Color、GradientPaint、
Texturepaint。
PaintContext 为描绘(paint)操作定义被包含的优化的环境。编程人员使用它实现通用
的描绘操作。
Stroke 产生一个被渲染图形的轮廓图形(描边)。其实现类有BasicStroke.

Class Description

AffineTransform(java.awt.geom) 表示一个2D仿射转换,完成由一个2D坐标向另一个2D坐标的线性转换。
AlphaComposite 实现接口:Composite
为图形、文本和图像实现基本的alpha混合规则。
BasicStroke 实现接口:Stroke
为图形的轮廓定义画笔样式。
Color 实现接口:Paint
为图形定义一种纯色。
GradientPaint 实现接口:Paint
为图形定义一种线性颜色渐变的填充模式。这种填充模式由P1点的C1色
渐变为P2点的C2色。
Graphics2D 继承于:Graphics
2d渲染的基础类,从java.awt.Graphics类继承而来。
TexturePaint 实现接口:Paint
为图形定义一种有质地(texture)的或图像的填充。 这种质地或图像是
从BufferedImage中产生的。

2.2渲染理念
Rendering Concepts
为能使用Java 2D API渲染一个图形,你需要先创建一个Graphics2D上下文并把图形对象传递到Graphics2D的渲染方法中。

你能够以下面的方式修改构成Graphics2D上下文的状态属性:
(1) 改变描边(stroke)的宽度;
(2) 改变描边结合点处;   
(3) 设置剪辑路径,把渲染限制在限定的区域内;
(4) 对图形对象进行移动、旋转、缩放和切变等渲染;
(5) 定义填充图形的颜色及模式;
(6) 指定应该参与组合的图形的数量。

Graphics2D为增强和改变状态属性,在图形上下文中定义了几种方法。大多方法产生一个能代表特定属性的对象,像Paint和Stroke对象等。

Graphics2D上下文保留了对这些属性对象的引用(references):它们并不是这些对象的克隆。如果你想修改Graphics2D上下文中某个属性对象,你需要调用恰当的Set方法来改变这些上下文。在渲染期间改变一个属性可能会引起难以预料和不稳定的行为。

2.2.1渲染过程
Rendering Process
当图形对象被渲染时,它的几何、图形和属性信息将会被组合起来重新计算。这些显示器上的像素值肯定会发生改变。
图形的渲染过程可分为四步:
(1) 如果图形被描边。Stroke属性将在Graphics2D上下文中产生一个包含描边路径的新的图形对象;
(2) 图形的路径图标通过Graphics2D上下文从用户空间向设备空间坐标转变;
(3) 使用clip属性,图形的路径将被剪辑;
(4) 剩下的图形——如果存在的话,会被Graphics2D上下文中的Paint和Composite等属性填充。

文本渲染和图形渲染类似,因为文本是作为单独的字形进行渲染而每个字形又是一个Shape对象。它们唯一不同在于Java 2D API必须决定使用什么字体(Font)进行渲染,并在渲染之前获得该字体的合适的字形。

图像的处理就略有不同了,转换和剪辑操作只在图像的限定范围内进行。颜色信息来自于图像自身,当图像像素在当前渲染界面上混合时,它的alpha通道将和当前的Composite属性结合起来使用。

2.2.2 控制渲染质量
Controlling Rendering Quality
Java 2D API让你自己决定图像对象是尽量的渲染还是尽可能高质量的渲染。你的选择被指定为示意(hint),通过Graphics2D上下方的RenderingHints属性来指定。但并不是所有平台都支持修改渲染模式,所以指定的渲染示意并不能保证会被运用。

RenderingHints类支持以下的渲染示意类型:
(1) Alpha interpolation --可以被设置为default、quality或者speed;
(2) Antialiasing --可设置为default、on或off;
(3) Color Rendering --可设置为default、quality或speed;
(4) Dithering --可设置为default、disable或enable;
(5) Fractional Metrics --可设置为default、on或off;
(6) Interpolation --可设置为nearest-neighbor、bilinear或bicubic;
(7) Rendering --可设置为default、quality或speed;
(8) Text antiliasing --可设置为default、on或off。

通过调用setRenderingHints,你可以设置或更改Graphics2D中的RenderingHints属性。如果示意设置为默认,那么系统将按该平台上的默认方式来渲染。

Antiliasing
当图形基元(primitive)在光栅图形显示设备上渲染时,由于图形和空白区域间的混淆,它们的边缘将呈现为锯齿状。弧线和对角线更容易出现锯齿现象,因为它们更热衷于附近出现的直线或曲线的路径相混合。这种现象在低分辨率的设备更值得注意,在这些设备上,锯齿现象与光滑的水平或垂直线形成鲜明的对比。

反锯齿(antiliasing)是一种用相对光滑的边缘来渲染对象的技术。与简单的把像素与周围直线或曲线像素混合不同,被渲染区域周围的像素具有更强的浓度,在一定程度上更接近于被渲染区域的像素。这样就使边缘像素变得柔软,并通过多倍的像素传递着转换开关的信息。然而,反锯齿要求更多的计算资源,因此降低了渲染速度。


Graphics2D渲染(Rendering with Graphics2D)上_第1张图片

2.2.3 描边属性
Stroke Attributes
给一个图形对象描边,例如对一个GeneralPath对象描边等效于用一逻辑画笔沿着GeneralPath运动。Graphics2D Stroke属性定义了画笔画下的痕迹的特性。
在Graphics2D 上下文中,由BasicStroke对象定义stroke属性。BasicStroke定义了诸如线条的宽度、端部的样式、线段结合点的结合方式以其有趣的(dashing)样式。想设置或改变Stroke属性,你可以调用setStroke方法。
Graphics2D渲染(Rendering with Graphics2D)上_第2张图片
BasicStroke支持的端部样式

Graphics2D渲染(Rendering with Graphics2D)上_第3张图片
BasicStroke支持的结合点样式

例如在下图中,第一幅图像使用了miter的结合点样式;第二幅使用了round的结合点样式、round的端部样式和dashing模式。
Graphics2D渲染(Rendering with Graphics2D)上_第4张图片

Graphics2D中使用Stroke属性的渲染方法有draw、drawArc、drawLine、drawOval、drawPolygon、drawPolyline、drawRect和drawRoundRect。当这些方法被调用时,指定图形的轮廓被渲染。Stroke属性定义了线条的特性,而Paint定义了画笔痕迹使用的颜色或样式。

例如,当draw( myRectangle )被调用时:
1、Stroke被应用到矩形的轮廓上;
2、被描边的轮廓转变为一个图形对象;
3、Paint被应用到图形轮廓的边缘的内部的像素上。
这个过程如下图所示:
Graphics2D渲染(Rendering with Graphics2D)上_第5张图片
2.2.4 填充属性
Fill Attributes
Paint对象代表了Graphics2D上下文的填充属性。通过调用setPaint方法可以把一个Paint添加到Grapihcs2D上下文中。

当图形或字体被绘制(Graphics2D.draw、Graphics2D.drawString),Paint被应用到表示该对象的描边轮廓的图形的内侧的像素上(其实就是绘制了图形)。而当一人图形被填充(Graphics2D.fill),Paint被应用到图形轮廓内部的所有像素上。
简单的纯色填充用setColor方法来装饰。Color类是Paint接口最简单的实现。
如用复杂的绘制样式(像渐变或用有质地的颜色)来填充图形,你就需要用Java 2D Paint的GradientPaint和TexturePaint类。这些类消除了使用简单的纯色创建复杂的图形的耗时性。下图说明了这两种能被GradientPaint和TexturePaint简单定义的填充方式:
Graphics2D渲染(Rendering with Graphics2D)上_第6张图片

当填充被用来渲染图形时,系统完成以下工作:
(1) 确定什么像素构成图形;
(2) 从Paint对象中获得每个像素的颜色;
(3) 为输出设备把颜色转换为合适的像素值;
(4) 把像素写到设备上。

批处理
Batch processing
为了能高效的处理这些像素,Java 2D API成批处理这些像素。一批既可以是给定扫描行上连续的像素集合也可以是一个像素块。批处理由以下两部完成:
(1) 调用Paint的createContext方法创建一个PaintContext,PaintContext保存了当前渲染操作和产生颜色所必须的信息上的相关性。在用户空间和设备空间上被填充的限定区域被传递到createContext方法上,在ColorModel中产生颜色并把转换从用户空间应用到设备空间。ColorModel被当作一个渲染示意对待因为不是所有Paint对象都能支持随意的ColorModel.(更多信息讲参见Color);
(2) getColorModel方法用来从PaintContext中获得ColorModel,用它来产生渲染颜色。

然后重复地调用getRaster方法为获得为每批保存实际颜色数据的Raster(光栅)。这些信息传递到渲染管道的下一个阶段,并使用当前的Composite对象绘制产生的颜色。

2.2.5剪辑路径
Clipping Paths
剪辑路径标识了图形或图像的需要渲染的那部分。当剪辑路径是Graphics2D上下文时,只有存在于该图形或图像剪辑路径内部的那部分被渲染。

通过调用setClip,你可以把一个剪辑路径添加到Graphics2D上下文中。任意的形状可以用来定义剪辑路径。

为了改变剪辑路径,你可以使用setClip指定一个新的路径,也可以调用clip来把剪辑路径改变为旧的剪辑路径和新的图形的交叉区域。

2.2.6 转换
Transformations
Graphics2D上下文包含了一个转换,用于在渲染期间把用户空间对象向设备空间转换。为了完成像旋转和缩放等附加的转换,你需要把其它的转换添加到Graphics2D上下文中。在渲染期间,这些附加的渲染了转换管道的一部分。

在上下文中,Graphics2D提供了几种不同的方式修改转换。其中最简单的是调用Graphics2D的转换方法:rotate、scale、shear和translate。你指定在渲染期间需要应用的转换特性,Graphics2D自动完成恰当的改变。

你也可以把一个AffineTransform和当前的Graphics2D转换明确的联系起来。AffineTransform对图元集合的元素执行诸如移动、缩放、旋转或切变等线性转换。当一个转换放到一个已存在的转换的后面时,最后面指定的转换被首先应用。为了和当前的转换相联系,你需要传递一个AffineTransform到Graphics2D.transform。

Graphics2D 类同样也提供了一个SetTransform方法,但这个方法绝不能被用来在一个已存在的转换上联系其它的坐标转换。setTransform方法重写了Graphics2D对象的当前转换,这个方向被用来完成其它的目的,诸如:
(1) 为打印分辨率应用一个绽放转换;
(2) 从父容器的原点开始的非零点完成绘制一个JComponent;
(3) 为了更容易查看而放大一个组件;
(4) 任何其它的情况,Grapihcs2D提供的用来使渲染效果更好而做的转换。
当对图形、文本和图像进行渲染后,setTransform方法可用恢复Graphics2D对象到未转换状态。

AffineTransform aT = g2d.getTransform();
g2d.transform(……); g2d.draw(……);
g2d.setTransform(aT);

Graphics2D同样提供了一个使用AffineTransfrom作为参数的drawImage的版本。这能使你能够对一个图像对象应用一个转换,如果该图像没有永久的修改转换管道。这个图像绘制出来,就像你已经在上下文中把这个转换与当前的转换发生联系一样。

Affine Transforms
仿射变换
Java 2D API提供了一个变换类:AffineTransform。该类被用来变换文本、图形和图像当这些图元被渲染时。你同样可以应用这些变换到Font对象上,用以创建一个新的字源。

一个仿射变换完成图元集合上的线性变换。它始终保持着把直线变换成直线,平行线变换成平行线;尽管这样,非平行线之前的点和角度之间的距离可能会发生改变。
仿射变换是基于如下形式的二维矩阵的:

Graphics2D渲染(Rendering with Graphics2D)上_第7张图片
变换可以被组合在一起,通过有效的创建应用到对象上的一系列或管道似的变换。这种组合被看作是一系列相互关联的组合。当一个变换和一个已存在的变换相关联时,比如AffineTransform.concatenate,最后指定的变换会被首先应用。一个变换也可以和已存在的变换发生预关联,这种情况下,最后指定的变换会被最后应用。

预变换完成与设备空间而不是用户空间相关的变换。例如,你能够使用AffineTransform.preConcatenate来完成与绝对像素空间相关联的变换。

2.2.6.1构建一个Affine Transform
Constructing an Affine Transform

AffineTransform提供了一组方便的方法来创建AffineTransform对象:
(1) getTranslateInstance
(2) getRotateInstance
(3) getScaleInstance
(4) getShearInstance

通过这些方法,你指定特定所需要的特定的变换,然后AffineTransform生成合适的变换矩阵。当然你也可以通过直接指定变换矩阵元素的方式构建一个AffineTransform。

2.2.7 混合属性
Composite Attributes
当两个对象重叠时,需要决定使用什么颜色来渲染这些重叠的像素。举例来说,如果一个红色矩形和一个蓝色矩形重叠,那么重叠区域的颜色应该被渲染成红色、蓝色还是它们两种中的某一组合呢?重叠区域的像素的颜色取决于哪个矩形在上面以其它的透明度。决定什么颜色渲染重叠区域的过程就称为“混合”。

以下两种接口构成了Java 2D组合模式的基础:Composite和CompositeContext。

为了指定哪种混合模式应该被应用,你需要调用setComposite方法把AlphaComposite对象添加到Graphics2D上下文中。
AlphaComposite是Composite接口的一个实现,支持许多不同的混合模式。该类的实例包括了描述如何把一种新的颜色和原有颜色混合的混合规则。

AlphaComposite类中最常用的混合规则是SRC_OVER,意思就是把新的颜色(源色)混合在原有颜色(目的色)的上面。


AlphaComposite Composite Rule Description Example
CLEAR Clear
DEST_IN Destination In
DEST_OUT Destination Out
DEST_OVER Destination Over
SRC Source
SRC_IN Source In
SRC_OUT Source Out
SRC_OVER Source Over

2.2.7.1 管理透明度

颜色的alpha值是它的透明度的计量值:通过百分数,它标示重叠区域上的先前的颜色有多少应该被渲染。不透明颜色(alpha = 1.0)不允许任何下面层上的颜色能显示出来,而透明色(alpha = 0.0)则允许下面层上的颜色全部显示。

当text和图形被渲染时,它的alpha值从Graphics2D上下文的Paint属性中继承而来。当图形和文本是反锯齿时,从Graphics2D上下文中的Paint中获得的alpha值由光栅路径上的像素覆盖信息组成。图像则保持了它们自己的alpha信息。

当你构造一个AlphaComposite对象时,你可以指定一个附加的alpha值。当你把这个AlhpaComposite对象添加到Graphics2D上下文时,这个附加的值添加任何被渲染的图形对象的通明度——因为每个图形对象的alpha值和AlphaComposite的alpha值执行相乘运算。

2.2.7.2 透明度和图像
Transparency and Images

图像中的每个像素都有自己的透明度。这个信息叫做alpha通道(alpha channel),在Grahpics2D上下文中和Composit对象协作渲染已绘制的图像。

例:下图中包含了三张图片,它们分别有着不同的通明度信息。在每种情况下,图像显示在一个蓝色矩形上。这个例子说明Graphics2D上下文包含了使用SRC_OVER作为混合操作的AlhpaComposite对象。

Graphics2D渲染(Rendering with Graphics2D)上_第8张图片

在第一幅图中,所有的像素要么完全不透明(狗的身体的部分)要么完全透明的(背景部分),这种效果经常在网页上使用。第二幅图上,狗身体部分所有的像素则使用一致的、非不透明(半透明)的alpha值来渲染,允许背景色透出来。第三幅图中,狗脏脸部分的像素是完全不透明的(alpha = 1.0),而随着与脸部距离的增加,alpha的值逐渐降低。

2.3创建Graphics2D上下文
Setting Up the Graphics2D Context

为了配置用于渲染的Graphics2D上下文,你需要使用Graphics2D的set方法来指定诸如RenderingHints、Stroke、Paint、clipping path、Composite和Transform等属性。

2.3.1设置渲染提示
Setting Rendering Hints

RenderingHints对象包含所有与对象渲染相关联的参数。为了在Graphics2D上设置渲染提示,你要创建一个RenderingHints对象并把它传递到Graphics2D.setRenderingHints中。

设置渲染提示并不意味着保证了所有的特定渲染法则会被运用:并不是所有的平台支持渲染模式的修改。

下面的示例中,反锯齿被激活,高质量的渲染模式也被设置:

qualityHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING , RenderingHints.VALUE_ANTILIAS_ON);
qualityHints.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHints(qualityHints);

2.3.2设置描边属性
Specifying Stroke Attributes

BasicStroke定义了应用到图形轮廓的特性,包括它的宽度、有趣的渲染模式、线段结合点处的结合方式以其应用到线条端部(如果存在的话)的渲染样式。为了把描边属性设置到Graphics2D上下文中,你需要首先创建一个BasicStroke对象并通过setStroke方法把它传递到Graphics2D上下文中。

2.3.2.1 设置描边宽度
Setting the Stroke Width

为了设置描边宽度,你要通过指定的宽度创建一个BasicStroke对象并调用setStroke方法。
在下面的例子中,描边的宽度设置为12点(points),并使用了默认的结合点和端部修饰。

wideStroke = new BasicStroke(12.0f);
g2.setStroke(wideStroke);

2.3.2.2 设置结合点和端部样式
Specifying Join and Endcap Styles

为了设置结合点和端部样式,你要用需要的属性值创建一个BasicStroke对象。
下面的示例中,描边宽度被设置为12 点(point),并设置了圆形的结合点和端部样式取代了它默认的值:

roundStroke = new BasicStroke(12.0f,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
g2d.setStroke(roundStroke);

2.3.2.3 设置破折线模式
Setting the Dashing Pattern

相对复杂的破折线模式也能通过BasicStroke对象轻松的创建。当你创建一个BasicStroke对象时,你需要指定两个用于控制该模式的参数:
(1) dash -- 一个表示该模式的数组。改变该数组中的元素意味着破折线的长度以其相邻的破折线之间的距离。0位置代表第一个破折线,1位置元素代表第一个空隙。
(2) dash_phase --破折线样式开始位置的偏移量。

在下面的示例中,两种不同的破折线模式被应用到直线中。在第一种样式中,破析线及其间隙之间的值为常量;第二中样式稍微复杂些,使用了6个元素的数组来定义这种模式。

float dash1[ ] = {10.0f};
BasicStroke bs = new BasicStroke{5.0f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0f,dash1,0.0f};
g2d.setStroke(bs);

Line2D line = new Line2D.Float(20.0f,10.0f,100.0f,10.0f);
g2d.draw(line);

float[ ] dash2 = {6.0f, 4.0f, 2.0f, 4.0f, 2.0f, 4.0f};
bs = new BasicStroke(5.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash2, 0.0f);
g2d.setStroke(bs);
g2d.draw(line);

上面两个示例中的破折线模式都使用了0 作为位移量,所以在每中示例中,破折线从该模式开始的位置开始绘制。这两种模式结果如下:

Graphics2D渲染(Rendering with Graphics2D)上_第9张图片
2.3.3 指定填充属性
Specifying Fill Attributes

当文本或图形被渲染时,Graphics2D中的Paint决定将使用填充的颜色或模式。

2.3.3.1 给图形填充渐变

GradientPaint类提供了一种简单的用于给图形填充从一种颜色到另一种颜色的渐变的方法。你创建一个GradeintPaint后,你需要指定起点和此处的颜色,末点和此处的颜色。填充颜色将沿着起点和末点间的直线恰当的发生改变。如下图所示:

Graphics2D渲染(Rendering with Graphics2D)上_第10张图片

在上图的第三颗星中,起点和末点都位于图形内部。P1前面的所有点的颜色和起点的颜色相同,P2点后面的颜色和末点颜色相同。

给一个图形填充渐变需要以下四步:
(1) 创建一个GradientPaint对象;
(2) 调用Graphics2D.setPaint;
(3) 创建一个Shape对象;
(4) 调用Graphics2D.fill(shape);

下面的示例中,给一个矩形用蓝-绿渐变进行了填充:

GradientPaint gp = new GradientPaint(50.0f, 50.0f, Color.blue, 50.0f, 250.0f, Color.green);

g2d.setPaint(gp);
g2d.fillRect(50,50,200,200);

2.3.3.2 用有质地的图像填充图形

TexturePaint类为重复的渲染图案提供了一种简单方法来填充图形。当你创建一个TexturePaint时,你需要指定一个BufferedImage作为要使用的图案。同样,你也可以把一个矩形传递给构造器,用这个矩形来定义图案重复的部分。如下所示:

Graphics2D渲染(Rendering with Graphics2D)上_第11张图片

用质地(texture)填充图形可分以下四步:
(1) 创建一个TexturePaint对象;
(2) 调用Graphics2D.setPaint;
(3) 创建待填充的Shape;
(4) 调用Graphics2D.fill(shape);
下面的示例中,一个矩形被一个从BufferedImage中创建的质地进行了填充:

//创建一个BufferedImage 块,尺寸为5*5
BufferedImage bi = new BufferedImage(5,5,BufferedImage.TYPE_INT_RGB);
Graphics2D big = bi.createGraphics();
//转换成BufferedImage图形来创建质地
big.setColor(Color.green);
big.fillRect(0 , 0 , 5 , 5);
big.setColor(Color.lightGray);
big.fillOval(0 , 0 , 5 , 5);

//通过BufferedImage来创建一个TexturePaint;
Rectangle r = new Rectangle(0 , 0, 5, 5);
TexturePaint tp = new TexturePaint(bi, r, TexturePaint.NEAREST_NEIGHBOR);

//把TexturePaint添加到图形上下文中
g2.setPaint(tp);

//创建并使用刚创建的质地渲染一个矩形
g2.fillRect(0,0,200,200);


2.3.4 设置剪辑路径
Setting the Clipping Path

定义一个剪辑路径,可分为两步:
(1) 创建一个表示你想要渲染的区域的Shape对象;
(2) 调用Graphics2D.setClip来使用这个shape对象作为Graphics2D上下文的剪辑路径。

缩小剪辑路径:
(1) 创建一个表示与当前剪辑相交叉的Shape;
(2) 调用clip把剪辑路径改变为当前剪辑路径与新的图形相交叉的剪辑路径。

下面的示例中,先从椭圆中创建一个剪辑路径,然后调用clip来改变它:

public void paint(Graphics g){

Graphics2D g2 = (Graphics2D) g;

//画布的宽度和高度
int w = getSize().width;
int h = getSize().height;
//创建一个椭圆,并把它作为剪辑路径
Ellipse2D e = new Ellipse2D.Float(w / 4.0f , h / 4.0f , w / 2.0f , h / 2.0f);
g2.setClip(e);

//填充画布,只有在剪辑区域内的部分才被渲染
g2.setColor(Color.cyan);
g2.fillRect(0,0,w,h);

//改变剪辑路径,把它设置为当前剪辑区域与新矩形交叉的部分
Rectangle r = new Rectangle(w / 4 + 10 , h / 4 + 10 , w / 2 - 20 , h / 2 - 20);
g2.clip(r); //注意与g2.setClip的区别

//填充画布,只有在新剪辑区域内的部分会被渲染
g2.setColor(Color.magenta);
g2.fillRect(0,0,w,h);

}

2.3.5 设置Graphics2D变换
Setting the Graphics2D Transform

为了能变换图形、文本和图像,你需要在渲染之前把一个AffineTransform对象添加到Graphics2D上下文中的变换管道中。当图形对象被渲染时,变换将会应用。

举例来说,绘制一个旋转了45度的矩形的步骤如下:
(1) 在执行任意的变换之前,先获得当前的Graphics2D变换。在对Graphics上下文本添加变换之前,你需要
调用Graphics2D上的getTransform方法,因为出于其它原因,Graphics上下文中可能已经存在了一个
变换,例如把Swing或其它轻量级组件添加到窗口中;
(2) 通过调用AffineTransform.getRotateInstance获得一个旋转变换;
(3) 调用Graphics2D.transform方法向变换管道中添加新的变换。不过不能使用setTransform方法来添加一个
新的坐标变换因为setTransform会重写上下文中当前的变换;
(4) 创建一个Rectangle2D.Float对象;
(5) 调用Graphics2D.draw渲染上面的矩形;
(6) 在你的变换的矩形上完成渲染后,调用setTransform重新把你在(1)中保存的原始变换设置到
Graphics2D中。

下面的示例中,用一个AffineTransform实例来把一个矩形旋转45度角:

AffineTransform aT = g2.getTransform();
Rectangle rect = new Rectangle2D.Float(1.0 , 1.0 , 2.0 , 3.0 );
AffineTransform rotate45 = AffineTransform.getRotateInstance(Math.PI / 1.0 , 0.0 , 0,0 );
g2.transform(rotate45);
g2.draw(rect);
g2.setTransform(aT);

下面的示例中,使用AffineTransform对象把一个文本串绕一个中心点旋转:
//定义一个渲染变换
AffineTransform at = new AffineTransform();
//使用一个translation变换为要旋转的文本设置空间
at.setToTranslation(400.0 , 400.0);
g2.transform(at);
//创建一个旋转变换来旋转文本
at.setToRotation(Math.PI / 2.0);
//在90度角的位置渲染四个字符串"Java"的复件
for ( int i = 0; i < 4; i++){
g2.drawString("Java", 0.0f , 0.0f);
g2.transform(at);
}

你可以使用相同的方式来变换图像对象——不管被渲染的图形的类型,Graphics2D上下文中的变换会在渲染期间应用。

为了把变换应用到图像上而不改变Graphics2D中的变换,你可以给drawImage传递一个AffineTransform对象:
AffineTransform rotate45 = AffineTransform.getRotateInstance(Math.PI / 4.0 , 0.0 , 0,0 );
g2.drawImage(myImage,rotate45);

变换同样可以应用到字体上来创建一个字体的修改版本。

2.3.6 指定一个混合模式
Specifying a Composition Style
AlphaComposite包含了颜色的混合规则,这些规则决定当一个对象和另一个对象重叠时将会渲染成什么颜色。为了给Graphics2D上下文中指定混合模式,你要创建一个AlphaComposite对象并通过setComposite传递给上下文。最常用的混合规则是SRC_OVER。

2.3.6.1 使用SRC_OVER规则
Using the Source Over Composition Rule

SRC_OVER混合规则把源像素(新的像素)组合到目的像素(原有像素)上面,这样重叠的部分就只显示了源像素的颜色。如果你开始渲染一个蓝色矩形,然后把一个红色矩形和它部分重叠,则重叠的部分会被渲染为红色。换句话说最后被渲染成的颜色将在最上面显示出来。

使用SRC_OVER规则的步骤:
(1) 通过调用getInstance创建一个AlphaComposite对象并指定SRC_OVER规则;
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER);
(2) 调用setComposite把AlphaComposite添加到Graphics2D上下文中;
g2.setComposite(ac);

一旦composite对象设置以后,重叠部分的将使用指定的规则来渲染。

2.3.6.2 增加组合对象的透明度
Increasing the Transparency of Composited Objects

AlphaComposite允许你指定一个额外的alpha值和源像素的alpha值相乘,以增大透明度。

举例:你创建一个AlphaComposite对象来使源像素有50%的透明度,指定alpha为 .5:
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f );

下面的例子中,一个SRC_OVER并指定alpha = .5的混合对象添加到了图形上下文中,使后面的图形具有了50%的透明度:

public void paint(Graphics g){

Graphics2D g2 = (Graphics2D) g;

g2.setColor(Color.red);
g2.translate(100,50);
// radians = degree * pie / 180
g2.rotate((45 * java.lang.Math.PI ) / 180 );
g2.fillRect(0, 0 ,100, 100);
g2.setTransform(new AffineTransform()); //设置特性
// 创建一个新的alpha composite
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER , 0.5f);
g2.setComposite(ac);
g2.setColor(Color.green);
g2.fillRect(50 , 0 , 100 , 100);
g2.setColor(Color.blue);
g2.fillRect(125, 75, 100, 100);
g2.setColor(Color.yellow);
g2.fillRect(50, 125, 100 ,100);
g2.setColor(Color.pink);
g2.fillRect(-25 , 75 , 100 , 100);
}

你可能感兴趣的:(Graphics2D渲染(Rendering with Graphics2D)上)