The Java 2D™ API 支持3种成像模型
- 由先前版本的JDK软件提供的生产者/
消费者(推)模型。
- 由Java™ 2 SDK版本引入的快速方式模型。
- 与快速方式模型兼容,并且将在即将到来的Java Advanced Imaging API中全面实现的管道(拉)模型。
下面的表格列举了这些成像模型的特征之间的对比。
这一章着眼于对象和直接方式的成像模型。Java 2D API的直接方式的成像类和接口提供了处理加载到内存中的像素
5.1 Interfaces and Classes
Java 2D™ API中直接方式成像的APIs可以分为6大类:接口、图像数
5.1.1 Imaging Interfaces
5.1.2 Image Data Classes
5.1.3 Image Operation Classes
5.1.4 Sample Model Classes
5.1.5 Color Model Classes
5.1.6 Exception Classes
Class
|
Description
|
---|---|
ImagingOpException
|
Extends:
RuntimeException
当一个BufferedImageOp或者RasterOp的过
|
RasterFormatException
|
Extends:
RuntimeException
当Raster中有无效的布局信息时被抛出。
|
5.2 Immediate Mode Imaging Concepts
5.2 直接方式成像的概念
直接方式的成像模型支持载入内存的、分辨率确定的图像。这种模型
如FigureBufferedImage
提供全面的图像处理。BufferedImage
可以在内存中直接创建,用来持有和操作从文件或者URL中取得的BufferedImage
可以通过任何以屏幕设备为目标的Graphics2D
对象显示,或者也可以通过合适的Graphics2D
配置场景呈现到其他目的地。BufferedImage
对象由另外两个对象组成:Raster(光栅)
对象和ColorModel(颜色模型)
对象。
Raster
类提供图像数据处理。它阐明图像的直角坐标,维护内存里的图像数DataBuffer
和SampleModel(取样模型)
。
DataBuffer
类掌管内存中的像素数据。
SampleModel
类解释缓冲中的数据,把数据以单独的像素或者某一矩形区域中的像
对于取样模型所提供的像素,ColorModel
类提供对该像素颜色的解释。
图像包还提供了另外一些类,定义了对BufferedImage
对象和Raster
对象的过滤操作。每一个图像的处理操作在实现BufferedImageOp
接口、RasterOp
接口或者同时两个接口的类中得到具体化。其中,由在操作类中定义filter
方法来执行实际图像操作。
Figure
其支持的操作有:
注意,如果只对显示和操作图像感兴趣,了解BufferedImage
类和执行过滤的类就可以了。反之,如果计划编写过滤器或者以直接BufferedImage
的相关类。
5.2.1 Terminology
5.2.1 术语
这里是下面讨论中常常出现的一些术语:
数据元素(或元素):一个基本类型的数据用来作为储存图像数据的DataBuffer
数组中的独立成员。元素在数据缓冲中的布局与该图像的SampleModel
对像素数据的解释无关。
取样(Samples):像素中的不同成员。SampleModel
提供了把DataBuffer
中的元素转换成像素及其取样的机制。 像素中的取样可以表现为特定颜色模型中的基值。比如,在RGB
成分(Components):像素的值,其实际值的得出依赖于IndexColorModel
可以帮助理解成分和取样之间的区别,这种模型中像素的成分是LookupTable
的索引值。
波段(Band):图像的所有相同类型采样的集合,例如所有红色
原色(Primaries): 在指定颜色模型的颜色值中的不同成员;例如,RGB模型中的颜
5.3 使用缓冲图像(BufferedImage)
BufferedImage
类是支撑直接成像模型的主要类。它管理内存中的图像,提供了存储Graphics
或者Graphics2D
的场景中呈现像素的方法。
5.3.1 创建一个缓冲图像(BufferedImage)
创建BufferedImage
,可以调用Component.createImage
方法;该方法返回一个BufferedImage
对象,其绘图特征与创建它的部件相匹配;由此创建的图像是不透明Component
相同,并且你不能改变图像的透明度。在使用双缓冲在部件中显示动
public Graphics2D createDemoGraphics2D(Graphics g) {Graphics2D g2 = null;int width = getSize().width;int height = getSize().height;if (offImg == null || offImg.getWidth() != width ||offImg.getHeight() != height) {offImg = (BufferedImage) createImage(width, height);}if (offImg != null) {g2 = offImg.createGraphics();g2.setBackground(getBackground());}/ / .. clear canvas ..g2.clearRect(0, 0, width, height);return g2;}
你也可以使用BufferedImage
提供的几个构造方法,在内存中创建一个空白BufferedImage
。
5.3.2 在屏外缓冲器中绘图
BufferedImage
类可以用来预先在屏外绘制图形元素,然后再拷贝到屏幕上。当图形
java.awt
包使屏外缓冲的使用变得容易,它允许你象在窗体上绘图一样在Image
对象上画图。在绘制屏外图像时可以使用所有Java 2D™ API所能提供的绘画特征。
屏外缓冲经常用来显示动画。例如,可以使用一个屏外缓存一次性地
Figure
5.3.2.1 创建一个屏外缓冲
最简单的创建图像屏外缓存方法是使用Component
.createImage
方法。
通过创建一个图像,并且该图像的颜色空间、深度和像素布局与窗体drawImage
能更快地工作。
也可以直接使用BufferedImage
的构造方法创建屏外缓存。这种方法在需要控制屏外图像的类型和透
BufferedImage
supports several predefined image types:
BufferedImage
支持几个预定义的图像类型:
TYPE_3BYTE_BGR
TYPE_4BYTE_ABGR
TYPE_4BYTE_ABGR_PRE
TYPE_BYTE_BINARY
TYPE_BYTE_GRAY
TYPE_BYTE_INDEXED
TYPE_CUSTOM
TYPE_INT_ARGB_PRE
TYPE_INT_ARGB
TYPE_INT_BGR
TYPE_INT_RGB
TYPE_USHORT_555_RGB
TYPE_USHORT_565_RGB
TYPE_INT_GRAY
BufferedImage
对象可以包含一个alpha(主成分)信道。在Figure
注意:除非你需要alpha数据实现透明,就象在Figure5
GraphicsConfiguration
提供了便利的方法,能自动创建图像格式与你的配置相兼容的缓冲图BufferedImage
对象所需要的信息。
5.3.2.2 在屏外缓冲中绘图
在BufferedImage中绘图,要先调用BufferedImage.createGraphics
方法,得到其返回的Graphics2D
对象。使用这个对象,你可以使用Graphics2D
的所有方法在BufferedImage中绘制基本图形、安置文
public void update(Graphics g){
Graphics2D g2 = (Graphics2D)g;
if(firstTime){
Dimension dim = getSize();
int w = dim.width;
int h = dim.height;
area = new Rectangle(dim);
bi = (BufferedImage)createImage(w, h);
big = bi.createGraphics();
rect.setLocation(w/2-50, h/2-25);
big.setStroke(new BasicStroke(8.0f));
firstTime = false;
}
// Clears the rectangle that was previously
drawn.big.setColor(Color.white);
big.clearRect(0, 0, area.width, area.height);
// Draws and fills the newly positioned rectangle to the buffer.
big.setPaint(strokePolka);
big.draw(rect);
big.setPaint(fillPolka);
big.fill(rect);
// Draws the buffered image to the screen.
g2.drawImage(bi, 0, 0, this);
}
5.3.3 直接操作缓冲图像(BufferedImage)中的数据
除了能在BufferedImage
中直接绘图之外,还可以通过两种方法直接存取和操作像素。实现了BufferedImageOp
过滤接口的类会帮助你实现这类功能,就象84页,“Image Processing and Enhancement”中讲述的那样。
使用BufferedImage
.setRGB
方法可以直接把一个指定的RGB值设置给一个像素或者一个像素数BufferedImage
相关联的WritableRaster
来操作像素。(参考“Managing and Manipulating Rasters” on page
5.3.4 对缓冲图像(BufferedImage)进行过滤操作
你可以使用实现了BufferedImageOp
接口的对象对BufferedImage
进行过滤。过滤操作以及实现过滤操作的类在“Image Processing and Enhancement” on page
5.3.5 呈现缓冲图像(BufferedImage)
把一个缓冲的图像呈现到特定的场景中,需要调用Graphics
场景对象的drawImage
方法。例如,在Component
.paint
方法中,使用该方法传递进来的Graphics对象的drawImage
方法就可以呈现图像。
public void paint(Graphics g) { if (getSize().width <= 0 || getSize().height <= 0) return; Graphics2D g2 = (Graphics2D) g; if (offImg != null && isShowing()) { g2.drawImage(offImg, 0, 0, this); } }
5.4 管理和操作Raster
BufferedImage
对象使用Raster
来管理像素的矩形数组。Raster
类定义了几个域变量来表示图像的坐标系:宽度、长度和原点。Raster
对象自己使用两个对象来管理像素,一个是DataBuffer
,另一个是SampleModel
。DataBuffer
为Raster存储像素(详述于pageSampleModel
则用来解释来自于DataBuffer
的像素(详述于page
5.4.1 创建一个Raster
大多数情况下,你不需要直接创建Raster
对象,因为你创建的BufferedImage
对象会提供这个对象。不过,有一个BufferedImage
的构造方法允许你以WritableRaster
对象为参数创建Raster
。
Raster
类也提供了许多静态的使用DataBuffers
和SampleModels
创建Raster
的工厂方法。当使用实现RasterOp
接口的类执行过滤操作时,你会用到这些工厂方法。
5.4.2 父子Raster
Raster
类混合了父、子概念,允许从同一父raster构建任意数量的缓getParent
方法来标识自身。
要创建一个子raster,可以使用Raster
.createSubRaster
方法。当被创建了一个子raster,你就可以用它的大小以及相
5.4.3 对Raster的操作
Raster
类定义了许多访问像素以及像素数据的方法。当你实现RasterOp
的接口(该接口提供了raster-level的过滤和图像数据
Raster.getPixel
方法可以使你得到独立的像素,它是该方法返回的一个包含每个样本Raster
.getDataElements
方法返回指定的一连串来自DataBuffer
的未经解释的图像数据。Raster
.getSample
方法返回一个单独像素的全部取样。getSamples
方法返回图像在指定区域内的指定波段的全部取样。
除了这些方法之外,你也可以通过Raster
类的实例变量访问数据缓冲和取样模型。这些对象提供了其他存取和Raster
中像素的方法。
5.4.4 WritableRaster子类
WritableRaster
子类提供了设置像素、取样的方法。与BufferedImage
相关联的Raster
实际上就是WritableRaster
,因此为操作其中的像素提供了完全的存取方法。
5.5 图像数据和DataBuffers
附属于Raster
的DataBuffer
中提供了一个图像数据的数组。当你直接或者通过BufferedImage
的构造方法创建Raster
时,你指定了以像素为单位的宽和高,还有该图像的SampleModel
。这些信息就可用来创建适当的数据类型及大小的DataBuffer
。
DataBuffer
有3个子类,分别提供不同类型的数据元素:
DataBufferByte
(represents 8-bit values)
DataBufferInt
(represents 32-bit values)
DataBufferShort
(represents 16-bit values)
DataBufferUShort
(represents unsigned short values)
象先前定义的,元素是数据缓冲中的数组的离散成员,并且成分或者DataBuffer
中元素的特定类型与SampleModel
所提供像素的特定类型之间可以有多种映射方式。实现映射并且提供DataBuffer
中获得指定像素的方法,就成了各个SampleModel
的子类要承担的责任。
DataBuffer
的构造器提供了创建指定大小并且包含指定个数波段的缓冲的方法。
不过,虽然你可以在DataBuffer
直接访问图像数据,一般情况下,更简单和更方便的是通过Raster
和WritableRaster
中的方法来完成这些任务。
5.6 从SampleModel中提取像素数据
SampleModel
抽象类定义了在不需要知道其底层数据如何存储的情况下提取图像采DataBuffer
中的图像高度和宽度,以及描述该DataBuffer
的数据类型以及所含波段的个数。由SampleModel
中的方法提供的图像数据是一个像素的集,其中每个像素由多个取样
java.awt.image
包提供了5种类型的取样模型:
ComponentSampleModel
—用来从特定格式的图像中提取像素。图像的存储格式为:采样储存在 DataBuffer
的某个储存区的分离的数据组元素中。
BandedSampleModel
—用来从特定格式的图像中提取像素。该图像的存储格式为:顺着在连续的数据元素里存储波段的方向,每个采样存储在分离的数据元素 里。
PixelInterleavedSampleModel
—用来从特定格式的图像中提取像素。该图像的存储格式为:顺着在连续的元素里存储像素的方向,每个采样到分开的数据元素中。
MultiPixelPackedSampleModel
—用来从特定格式的图像中提取像素。该图像的存储格式为:在一个数据元素力存储多个单采样的像素。
SinglePixelPackedSampleModel
—用来从特定格式的图像中提取像素。该图像的存储格式为:单个像素的采样数据存储在 DataBuffer
的第一个波段中的某一数据组元素里。
由SampleModel
表示的像素数据可能直接与特定颜色模型对颜色数据的表示相关或者
有三类存取图像数据的方法。getPixel
方法通过使用一个适合于每个取样的入口,返回一个数组形式的完整getDataElement
方法提供了对存储于DataBuffer
的未加工、未解释数据的存取。getSample
方法提供了对指定波段的像素成分的存取。
5.7 ColorModels与颜色
除了使用Raster
管理图像数据,BufferedImage
还包含了ColorModel
用来解释像素的颜色值。ColorModel
抽象类定义了在与其相关联的ColorSpace
中转化像素数据到的颜色值的方法。
java.awt.image
包提供了4种颜色模型:
PackedColorModel
—一个抽象的ColorModel
,表现其颜色成分直接嵌入成为该整数像素的数据位的像素值。DirectColorModel
是PackedColorModel
的子类。
DirectColorModel
— 一个ColorModel
可以表现含有RGB颜色成分,并且其颜色成分直接嵌入作为该像素自身数据位的像素。 DirectColorModel
模型的观感与X11 TrueColor相似。
ComponentColorModel
—ColorModel
可以处理任意的ColorSpace
以及由颜色成分构成的、与ColorSpace
相匹配的数组。
IndexColorModel
—一个ColorModel
,所表现的像素值是一个sRGB颜色空间的固定颜色表的索引。
ComponentColorModel
和PackedColorModel
是刚出现在Java™ 2 SDK发行版本中的。
基于DataBuffer
中的数据,SampleModel
把一个像素提供给ColorModel
,ColorModel
进而把该像素解释成颜色。
5.7.1 查找表(Lookup Table)
查找表包含了用于存有一个或多个信道或者图像成分的数据;例如,java.awt.image
包定义了两种扩展了LookupTable
抽象类的查找表,一个容纳byte数据,一个容纳short数据ByteLookupTable
和ShortLookupData
)。
5.8 图像处理及图像增强
图像包提供了一对定义了对BufferedImage
和Raster
进行操作的接口:BufferedImageOp
和RasterOp
。
实现这些接口的类包括AffineTransformOp
,BandCombineOpColorConvertOp, ConvolveOp
,LookupOp, RescaleOp
。这些类可以用于对图像进行几何变形、模糊、锐化、增强对比度、
Figure
下面的代码举例说明边缘探测:
float[] elements = { 0.0f, -1.0f, 0.0f, -1.0f, 4.f, -1.0f, 0.0f, -1.0f,0.0f }; BufferedImage bimg = new BufferedImage(bw, bh,BufferedImage.TYPE_INT_RGB); Kernel kernel = new Kernel(3, 3, elements); ConvolveOp cop = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null); cop.filter(bi, bimg);
Figure
下面的代码示范了查找表操作:
byte reverse[] = new byte[256]; for (int j = 0; j < 200; j++) { reverse[j] = (byte) (256 - j); } ByteLookupTable blut = new ByteLookupTable(0, reverse); LookupOp lop = new LookupOp(blut, null); lop.filter(bi, bimg);
Figure
下面的代码片断举例说明了比例重调:
5.8.1 应用图形处理操作
卷积是大多数空间过滤算法的基本处理过程。卷积是对图像中的每个
下面的代码片断举例说明了怎样使用实现ConvolveOp
操作的类。在这个例子中,源图像中的每个像素是其周围的8个像素
变量simpleBlur包含一个新的ConvolveOp
实例,在BufferedImage
或Raster
上实现模糊处理。假设sourceImage和destImagBufferedImage
的实例,当你调用ConvolveOp
类的核心方法filter
时,它赋给目标图像中的每个像素以源图像中对应像素及其周围8个
在这个例子中卷积的kernel可以由下面的矩阵,连同指定的4
当图像经过卷积,目标图像中的每个像素的值是通过使用kerne
下面的公式显示了 当卷积执行后,kennel中的权是怎样与源图像中的像素关联
目标像素的值是kernel与相应源像素的乘积之和。在很多简单
这例子中卷积的kernel相对简单。它平均地给源图像中的每个Kernel
对象,这个设置给ConvolveOp
构造方法中的对象,决定着要执行的过滤的类型。通过设置别的值,
下面的代码片断举例说明了使用卷积实现的锐化:
float[] elements = { 0.0f, -1.0f, 0.0f, -1.0f, 5.f, -1.0f, 0.0f, -1.0f,0.0f }; Kernel kernel = new Kernel(3, 3, elements); ConvolveOp cop = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null); cop.filter(bi, bimg);
mark
1. 东西都是相通的,rgb,argb,转化,以及可以通过byte[]数据直接构造raster来构造 BufferedImage, 或者反向操作每个像素点。
2. 通过createGraphics获取图像句柄,可在图像上实现绘制直线、多边形、字符串等。
3. 以及一些地图上等值面可以以网格点的形式绘制图像的方式贴上去。