610 Understanding Java Imaging Interfaces
610 了解Java的图象接口
As you have learned, the AWT librarylets your applets load and display an image from a GIF or JPEG file. However,if you need to create images from other sources, or to manipulate an existingimage, you must understand Javas imaging interfaces defined in thejava.awt.image package.
你已经了解,AWT库使小应用程序能从GIF或JPEG文件装入和显示一幅图象. 但是,假如你要从其它来源创建图象,或处理一个已有图象,你必须了解在Java.awt.image包中定义的Java图象接口.
The ImageProducer interface lets youdefine an object, known as an image producer, that produces data for an image.For example, the MemoryImageSource class implements the ImageProducer interfacefor creating image data from an integer array. To get the image producer for anImage object, you call the getSource method.
ImageProducer(图象发生器)接口用来定义被称作ImageProducer的对象,它可以为一图象产生数据.例如,MemoryImageSource类实现了ImageProducer接口,它为整型数组建立图象数据.为了为图形对象获得图象发生器, 可调用getSource方法.
The ImageConsumer interface lets youdefine an object, known as an image consumer, that receives image data. Forexample, the PixelGrabber class implements the ImageConsumer interface, whichlets you extract image data and place the data in an integer array.
ImageConsumer(图象用户)接口用来用来定义被称作Image Consumer的一种对象,它用来接收图象数据. 例如, PixelGrabber类实现了ImageConsumer接口,它用来提取图象数据并把数据放进一整型数组中.
The ImageFilter class, as shown inFigure xx, takes image data from an image producer, processes the data, andthen sends the data to an image consumer. For example, your applet might createan image filter to brighten the color of an image or to rotate an image.
ImageFilter(图象滤波器)类, 如图610所示, 从图象发生器取得数据, 并处理这些数据,然后将数据送给一图形用户. 例如,你的小应用程序可以创建一个图象滤波器来增亮一幅图象的颜色或转动一幅图象.
Figure 610The Image filtering process.
图610 图象滤波过程
611 Understanding the Default Color Model
611 了解缺省色彩模式
To process image data, you must understand how programs storepixel data in memory. Java uses a color model to define how other imagingclasses should interpret pixel data to extract color information. The defaultcolor model stores the color of a single pixel in a 32-bit integer, as shown inFigure 611.
为了处理图象数据, 你必须了解程序是怎样将象素数据存放在内存中的.Java利用一种色彩模式来定义其它图象类应怎样解释象素数据来获的色彩信息. 缺省的色彩模式每个象素是用如图611所示的32位整型数表示.
Figure 611 Javas defaultcolor mode.
图611 Java的缺省色彩模式
The model uses eight bits to store each of the blue, green, andred colors and the alpha component. Bits 0-7 of the 32-bit integer stores theblue component, bits 8-15 store the green component, bits 16-23 store the redcomponent, and bits 24-31 store the alpha component. The alpha componentdefines the pixels transparency. An alpha value of 0 means the pixel istransparent and a value of 255 means the pixel is opaque. Using the alphacomponent, Java provides support for the display of transparent GIF images.With alpha transparency, you can even define pixels that are semi-transparent.
该模式利用四个8位来分别存放红,绿,兰以及alpha四种成份. 32位整型数中的0-7位用于存放兰色成份,8-15位用于存放绿色成份,16-23位用于存放红色成份,24-31位用于存放alpha成份. alpha成份定义了象数的透明性. alpha值为0,意谓象素透明, 而alpha值为255, 意谓象素完全不透明. 利用alpha成份后, Java为显示透明的GIF图象提供了支持. 利用alpha透明性, 你甚至也可以定义象素的半透明性.
612 Understanding theDirect Color Model
612 了解直接色彩模式
In the previous tip, you learned that Javas default color modeluses eight bits per color to store a pixels red, green, and blue colors. Withinyour programs, there may be times when you will want to use a different numberof bits for each component. The DirectColorModel class lets you define how manybits Java should use to represent each color component. To create a new directcolor model, you use one of the following contructor methods:
在上一TIP中, 你已知Java的缺省色彩模式是各用四个8位来分别存放红,绿,兰以及alpha四种成份. 在你的程序中, 你有时可能想用和上述不同的位数来表示各种成份.DirectColorModel(直接色彩模式)类就可让用户来指定Java用几位来表示每一种成份.为了创建一种直接色彩模式, 你可以利用以下的构造函数方法:
DirectColorModel(intbits, int rmask, int gmask, int bmask);
DirectColorModel(intbits, int rmask, int gmask, int bmask,
int amask);
The bits parameter specifies the number of bits required tostore the color of one pixel. The rmask, gmask, bmask, and amask parameterspecifies the bitmask Java uses to extract color data for the red, green, blue,and alpha components. If you do not specify the amask parameter, Java assumesthe pixel data does not contain the alpha component. The following statementuses the DirectColorModel to create a direct color model that matches thedefault color model:
参数bits用来指示存放一个象素的色彩所需的位数. 参数rmask, gmask, bmask, 和amask 代表分别为红,绿,兰和alpha成分抽取色彩数据的位屏蔽(bitmask). 如果你不指定参数 amask的值, Java假设象素数据不包含alpha成分. 以下的语句利用了DirectColorModel 来创建一个和缺省色彩模式相同的直接色彩模式.
DirectColorModel(32,0x00FF0000,0x0000FF00,0x000000FF,0xFF000000);
The following statement, for example, defines a color model thatuses 4 bits of red data, 6 bits of green data, 5 bits of blue, and no alphacomponent:
例如,以下语句在 定义一色彩模式时利用4位的红色数据,6位的绿色数据,5位的兰色数据,而没有alpha成分:
DirectColorModel(32,0x00007800, 0x000007E0, 0x0000001F);
613 Creating an Image Usingthe MemoryImageSource Class
613 利用MemoryImageSource(内存图象源)类创建一幅图象
As you have learned, within your programs you can create animage using a GIF or JPEG image file. Java also lets you create an image usingdata in memory. The MemoryImageSource class produces an Image from an array ofinteger pixel values. To create an Image object, you can use the followingMemoryImageSource constructor, as shown:
你已知道在你的程序中可以利用GIF或JPEG图象文件来创建一个图象. Java也能让你利用内存中的数据来创建一个图象. MemoryImageSource类根据一整型的象素值数组来生成一个图象. 为了创建一个图象对象,你可以利用构造函数MemoryImageSource,如下:
MemoryImageSource(intw, int h, int pix[], int off, int scan);
The w and h parameters specify the image dimensions. The pixparameter specifies the integer array that contains the pixel values. The offparameter specifies the data offset within the pix array. The scan parameterspecifies the width of one line of pixel data in the pix array. Therefore, yourprogram would locate the value of a pixel at the location (m, n) at the index(n * scan + m + off) of the pix array.The following applet, mem_isource.java,creates a small (4x7 pixels) image using a MemoryImageSource object. The appletthen displays the image as well as a scaled version within the applet window,as shown in Figure 613:
其中, 参数 w 和h 用来指定图象的大小. 参数 pix 是一个整型数组, 它包含着象素的值. 参数 off 指定了数组中数据的偏移量. 参数 scan 是 pix 数组中一根线的宽度.因此,你的程序应把位于(m,n)的一个象素值放在pix数组的下标 n*scan+m+off 处.以下的小应用程序, mem_isource.java, 利用MemoryImageSource对象创建了一个4*7个象素的小图象. 然后小应用程序把图象如图613所示那样在小应用程序窗口中用一个放大的版本进行显示:
import java.applet.*;
import java.awt.*;
importjava.awt.image.*;
public classmem_isource extends Applet {
int mem_pix[] = { 0x00000000, 0xFFFF0000,0xFFFF0000, 0x00000000,
0xFFFF0000, 0x00000000,0x00000000, 0xFFFF0000,
0xFFFF0000, 0x00000000, 0x00000000,0xFFFF0000,
0x00000000, 0xFFFF0000,0xFFFF0000, 0x00000000,
0xFFFF0000, 0x00000000,0x00000000, 0xFFFF0000,
0xFFFF0000, 0x00000000,0x00000000, 0xFFFF0000,
0x00000000, 0xFFFF0000,0xFFFF0000, 0x00000000
};
Image mem_img;
public void init()
{
mem_img=createImage(newMemoryImageSource(4,7,mem_pix,0,4));
}
public void paint (Graphics g)
{
g.drawImage (mem_img, 5, 5, this);
g.drawImage (mem_img, 20, 0, 80, 140, this);
}
}
kaj explain code processing
Figure 613 An image createdwith MemoryImageSource.
图613 用MemoryImageSource创建一幅图象
614 Understanding the IndexColor Model
614 了解索引色彩模式(Index Color Model)
fix xxx
In Tip xxx, you learned that one way Java can represent screencolors is to store RGB (red, green, and blue) color data for each pixel. Theindex color model provides a more compact model for storing pixel color data.Using the index model, pixel data does not represent color values directly.Instead, the pixel data is an index to a color lookup table that contains theRGB and alpha values. In fact, the 256 color standard VGA mode on IBMcompatible PCs is based on an index color model. The advantage of an indexcolor model is that it can reduce the storage size of the pixel data
without limiting the colors that it can display. Thedisadvantage is that the index color model limits the number of simultaneouscolors that the image can have. To create an index color model object, use oneof the following IndexColorModel contructor methods:
在TIP XXX 中,你已了解Java表示屏幕颜色的一种方式是为每个象素存储RGB(红,绿,兰)色彩数据. 而索引色彩模式为象素色彩数据的存储提供了一种更为紧凑的模式. 利用了索引色彩模式, 象素数据不直接代表色彩值, 而是指向含有RGB和alpha值的色彩查找表(colorlookup table)的一个索引值(下标号). 事实上, 在与IBM PC机兼容的机器上,标准VGA中的256色模式就是一种索引色彩模式. 索引色彩模式的优点在于它能减少象素数据的存储尺寸而不限制它能显示的色彩. 而索引色彩模式的缺点则在于它限制了图象能同时显示出来的色彩数目.为了创建一索引色彩模对象,用以下的IndexColorModel构造函数方法:
IndexColorModel(intbits, int size, byte r[], byte g[],
byte b[]);
IndexColorModel(intbits, int size, byte r[], byte g[], byte b[],
int trans);
IndexColorModel(intbits, int size, byte r[], byte g[], byte b[],
byte a[]);
IndexColorModel(int bits,int size, byte cmap[], int start,
boolean hasalpha);
The bits parameter specifies the number of bits the modelrequires to store the index value for one pixel. The size parameter specifiesthe size of the color-lookup table and, consequently, the size of the r, g, b,and a arrays. The trans parameter in the second constructor specifies the indexfor transparent color. The a array in the third constructor specifies an arrayof alpha (transparency) settings. In the last constructor, you specify the RGBand alpha color values in sequence within the cmap array. The first byte in thecmap array stores the 8-bit red component value, the
second byte stores the green component, and the third bytestores the blue component. If the hasalpha parameter is true, then the fourthbyte in the cmap array stores the alpha transparency component.
参数 bits 指定该模式存储一个象素的索引值所需的位数. 参数size指定了色彩查找表大小, 因此, 也决定了数组r,g,b,a的大小. 第二个构造函数中的参数 trans 指定了透明色的索引值. 第三个构造函数中的数组 a 是alpha(透明度)值的设置数组. 在最后一个构造函数中, 要你把RGB和alpha的色彩值按顺序存放在数组cmap中. cmap数组的第一字节用来存放8位的红色分量,第二字节用来存放绿色分量,第三字节存放兰色分量. 如果参数hasalpha 为真, 则cmap的第四字节用来存放透明分量.
615 Creating an Image UsingMemoryImageSource with the Index Color Model
615 利用索引色彩模式的内存图象源创建一幅图象
As you learned in Tip 614, the MemoryImageSource class producesan Image from an array of integer pixel values. To create a MemoryImageSourceobject that uses an index color model, you use the following constructormethod:
你在 TIP 613 中已知道, MemoryImageSource类根据整型象素值数组来创建图象. 为了创建一个使用索引色彩模式的MemoryImageSource对象,你可使用以下的构造函数方法:
MemoryImageSource( int w, int h, ColorModel cm, int pix[], int off, int scan );
The following applet, index_memsource.java, is similar to themem_isource.java applet you created in Tip 613. The difference between theprograms is that the index_memsource.java applet creates an index color modelwith two colors and uses it as the color model for the MemoryImageSourceobject:
以下的小应用程序,index_memsource.java, 和你在TIP 613 中创建的小应用程序mem_isource.java 类似. 程序的差别是小应用程序index_memsource.java使用两种颜色创建一个索引色彩模式, 并把它用作对象MemoryImageSource的颜色:
import java.applet.*;
import java.awt.*;
importjava.awt.image.*;
public classindex_memsource extends Applet {
int mem_pix[] = { 0x00, 0x01, 0x01, 0x00,
0x01, 0x00, 0x00, 0x01,
0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x01, 0x00,
0x01, 0x00, 0x00, 0x01,
0x01, 0x00, 0x00, 0x01,
0x00, 0x01, 0x01, 0x00};
/* index 0-black 1-magenta */
byte ra[] = {0, (byte) 255};
byte ga[] = {0, 0};
byte ba[] = {0, (byte) 255};
Image mem_img;
public void init()
{
IndexColorModel cm = new IndexColorModel(8, 2, ra, ga, ba);
mem_img = createImage(newMemoryImageSource(4, 7, cm,
mem_pix, 0, 4));
}
public void paint(Graphics g)
{
g.drawImage (mem_img, 5, 5, this);
g.drawImage (mem_img, 20, 0, 80, 140, this);
}
}
kaj explain the code
616 Using the PixelGrabber Class to Extract PixelValues
616 使用PixelGrabber类来提取象素(色彩)值
In the previous tip, you learned that you can convert an integerarray into an image source (producer) object. Conversely, you can also use aninteger array as the consumer of image data. For example, to brighten thecurrent image, your program might get the image pixels and change thecorresponding color values. The PixelGrabber class lets your programs extractpixel values from an image source. To use the PixelGrabber, you first need tocreate a PixelGrabber object using the following constructor method:
在上一TIP中你已了解可以把一个整型数组转换成图象源(即图象发生器)对象. 反之,你也可以把一个整型数组看作图象数据的用户. 例如, 为了增加当前图象的亮度,你的程序可以取出图象的象素,改变对应的色彩值. PixelGrabber类的供能就是让你从一图象源取出图象的象素值. 为了使用PixelGrabber, 你首先必需利用以下的构造函数方法创建一PixelGrabber对象:
PixelGrabber(Imageimg, int x, int y, int w, int h, int pix[],
intoff, int scansize);
PixelGrabber(ImageProducerip, int x, int y, int w, int h,
int pix[], int off, int scansize);
You can specify the image source as an Image object using theimg parameter or an ImageProducer object using the ip parameter. The x, y, w,and h parameters specify the rectangular region in the image that thePixelGrabber extracts. The pix parameter specifies the integer array thatstores the pixel values. The off parameter specifies the offset of the datawithin the pix array, and the scan parameter specifies the width of the oneline of pixel data in the pix array.
The second step to extracting pixel values is to call thegrabPixels method, which starts the extraction process. Then, you should callthe status method to find out whether or not the operation was successful. Thefollowing applet, pix_grab.java, extracts pixel values from a 30x30 rectangularregion using the PixelGrabber. The applet then displays an ASCII version of theimage in the console window, as shown in Figure 616:
你可以利用参数 img 指定图象源作为图象对象, 或用参数 ip 指定图象源作为图象用户. 参数x,y, w, 和h 指定了 PixelGrabber 提取的图象中的一个矩形区域. 参数 pix是一个存放象素值的整型数组. 参数off指定了数据在 pix 数组中的偏移, 而参数scan指定了在 pix 数组中的一根象素数据线的宽度.
提取象素值的第二步是调用grabPixels方法, 它开始了提取的过程. 然后, 你应调用status方法来确定该操作是否成功. 以下的小应用程序 pix_grab.java 利用了PixelGrabber方法从大小为30*30个象素的一个矩形区中提取象素值. 然后小应用程序在控制台窗口中显示了图象的ASCII版, 如图616所示: {图有错?}
import java.applet.*;
import java.awt.*;
importjava.awt.image.*;
public class pix_grabextends Applet {
Image mem_img;
public void init()
{
mem_img = createImage(20,20);
}
public void start()
{
// draw to offscreen buffer
update (mem_img.getGraphics());
int pixels[] = new int[20 * 20];
PixelGrabber pg = newPixelGrabber(mem_img, 0, 0, 20, 20,
pixels, 0, 20);
// grab from offscreen buffer
try {
pg.grabPixels();
}
catch (InterruptedException e)
{
System.out.println("grabbererror" + e);
return;
}
if ((pg.status() &ImageObserver.ABORT) != 0)
{
System.out.println("grabbererror");
return;
}
for (int y = 0; y < 20; y++)
{
for (int x = 0; x < 20; x++)
{
if (pixels[y * 20 + x] ==Color.red.getRGB())
System.out.print("*");
else
System.out.print ("");
}
System.out.println();
}
}
public void paint(Graphics g)
{
g.setColor (Color.red);
g.drawLine (0, 0, 19, 19);
g.drawLine (0,19, 19, 0);
}
}
Figure 616 Displaying anASCII version of a pixel image.
图616 显示一象数图象的ACII版
617 Getting IndividualColor Components
617 取出单个的色彩成份
In previous tips, you have learned that your programs can encodepixel data in many different ways based on color models. Decoding pixel data toget color components for different models can be a complex task. Fortunately,the ColorModel class offers several methods your programs can use to extractthe color component from a pixels data. Each method returns a specificcomponent, as shown:
在前面的TIP中,你已知道了你的程序可以根据色彩模式用许多方式对象素数据进行编码. 对不同的模式的象素数据进行译码,以取出色彩的分量,是一项复杂的工作. 幸运的是,ColorModel 类为你的程序提供了一些方法,可以用来从象素数据取出色彩的成份,每一个方法返回一种色彩分量,如下:
int getRGB(int pixel);
int getAlpha(intpixel);
int getRed(int pixel);
int getGreen(intpixel);
int getBlue(int pixel);
The getRGB method converts the pixel data into the 32-bitalpha-RGB representation, which is based on the default color model. ThegetRed, getGreen, getBlue, and getAlpha methods extract the 8-bit value of thered component, green component, blue component, and alpha component for a givenpixel value.
GetRGB方法将象素数据转为32位 alpha-RGB来表示,这是基于缺省的色彩模型。getRed, getGreen, getBlue 与 getAlpha 四个方法用来提取一个像素的红、绿、蓝及 alpha 成分。
618 Understanding ColorSpace (RGB vs HSB)
618 了解色彩空间(RGB 和 HSB)
As you know, programs specify different colors using differentred, green, and blue component values. The RGB color cube, as shown in Figure618.1, provides a graphical representation for the RGB color model.
你已经了解程序是利用不同的红,绿,兰分量值来指定不同的颜色. 图618.1所示的RGB色彩立方体为RGB色彩模型提供了一个图形表示.
Figure 618.1 The RGB colorcube model.
图618.1 RGB色彩立方体模型
The RGB color model is not the only way to represent colors. Forexample, you can represent the same color you are expressing using RGB settingsin terms of hue, saturation, and brightness. The hue component specifies a purecolor, such as red or cyan. The saturation component specifies how deep orfaded the color is. The brightness component specifies the intensity of thecolor. Figure 618.2 illustrates the hue, saturation, and brightness (HSB) colorcone.
RGB色彩模型不是表示色彩的唯一方法. 例如, 你可以把用RGB设置所表示的同一种颜色利用色调(hue),饱和度(saturation),以及亮度(brightness)三个来表示. 色调分量指定了一种单纯的颜色,如红或青(cian). 饱和度分量指定颜色有多少浓(饱和),亮度就是色彩的明亮程度. 图618.2 说明了色调,饱和度,亮度(HSB)的色彩圆锥体.
Figure 618.2 The HSB color cone model.
图 618.2 HSB色彩立方模型
619 Using Color SpaceConversion Methods
619 色彩空间转换方法的使用
In the previous tip, you learned that you can represent the samecolor in an RGB color space and in an HSB color space. When your programprocesses pixel data, there may be times when you want to adjust the color by hue,saturation, or brightness. In such cases, you must use the Color classcolor-space conversion methods, shown in the following statements:
在以上 TIP 中你已知道,可以利用RGB色彩空间和HSB色彩空间来表示同一种颜色.当你的程序处理图象数据时,你有时会想要用色调,饱和度,亮度三个参数来调色. 如果是这样, 你可以用Color 类的色彩空间转换方法,如以下语句所示:
int HSBtoRGB(floathue, float saturation, float brightness);
float[] RGBtoHSB(intr, int g, int b, float hsbvals[]);
The HSBtoRGB method returns an RGB color value for a given HSBcolor value.The Color class represents the hue parameter in terms of radians,while the saturation and brightness parameters range from 0.0 to 1.0.TheRGBtoHSB returns an HSB color value in a float array for a given RGB colorvalue. You specify the hsbvals array parameter to store the return values orset it to null to have the RGBtoHSB method allocate the storage.
HSBtoRGB方法为每一个HSB色彩值返回一个RGB色彩值. Color类用弧度来表示hue参数, 而用0.0到1.0范围中的实型数来表示饱和度,亮度两个参数. RGBtoHSB方法为每一个RGB色彩值返回一个HSB色彩值. 你把返回值存放在数组参数hsbvals中, 或者将其设为null,以便让RGBtoHSB方法来分配存储器.
620 Using an Image Filter
620 使用图象滤波器
As you have learned, an image filter is software that you createwhich takes image data from an ImageProducer object, processes the data, andthen sends the result to an ImageConsumer object. To use an image filter,perform the following steps:
你已知道,一个图象滤波器是你创建的一个软件, 它从对象ImageProducer获得数据,进行处理, 然后把结果送给一个ImageConsumer对象. 为了使用一个滤波器,可按以下的步骤进行:
1. Create an image filter object by calling the filtersconstructor. For example, the following statement creates an ImageFilter objectand uses the applet-defined MyImageFilter class to initialize the object:
1. 调用滤波器构造函数创建一个filter对象. 例如, 以下的语句创建一个ImageFilter对象,并用小应用程序中已定义的MyImageFilter类来初始化该对象:
ImageFilter f = newMyImageFilter();
2. Next, you must create an image producer. In many cases, thesource of the image corresponds to the image file. As such, you would create anImage object using the following code:
2. 然后, 你必须创建一个图象生成器. 在许多情况下, 图象源对应与图象文件.因此,你可以利用以下的代码来创建一个图象对象:
Image img =getImage(getCodeBase(), "image.gif");
You can then get a reference to the image by calling the Imageclass getSource method.
然后你就可通过调用Image类的 getSource方法来取得该图象的一个引用.
3.Create a FilteredImageSource object to connect the imageproducer with the image filter, as shown:
3. 创建一个FilteredImageSource 对象, 把图象生成器和图象滤波器连接起来,如:
ImageProducerproducer=new FilteredImageSource(img.getSource(),f);
The FilteredImageSource is an image producer that produces thefiltered image.
FilteredImageSource是产生滤波后图象的图象生成器.
4. The last step is to create the resulting image using thecreateImage method:
4. 最后一步是利用 createImage 方法创建结果图象:
Image filtered_img =createImage(producer);
do we have a complete example
这样我们就得到了一个完整的例子.
621 Using theRGBImageFilter
621 RGB图象滤波器 (RGBImageFilter) 的使用
The RGBImageFilter class, a subclass of ImageFilter, is designedfor building an image filter that calculates the new pixel color based solelyon the pixels current color value and position. However, the new pixel valuethat the RGBImageFilter class produces does not depend on the value of otherpixels in the image. Color processing that only considers one pixel at a timeis called point processing.
RGBImageFilter类是ImageFilter类的子类, 它是为创建一种只根据象素的当前值和位置来计算新象素色彩值的图象滤波器而设计的. 由 RGBImageFilter 类所产生的新象素色彩值不依赖于图象中其它象素的值. 每次只考察一个象素的图象色彩数据处理方式点处理(point processing).
For each pixel in the image, the RGBImageFilter class calls thefilterRGB method, passing to the method the pixels x, y coordinates andalpha-RGB color values. When you create your own RGBImageFilter class, younormally override the filterRGB method to process the pixel data, and thenreturn the new color value for that pixel.
对图象中的每一个象素, RGBImageFilter类调用了 filterRGB 方法, 把象素的x,y坐标和alpha-RGB值传递给此方法. 当你创建你自己的 RGBImageFilter 类时, 你通常利用filterRGB方法来处理象素数据, 然后为此象素返回新的色彩值.
The following applet, brightness.java, constructs aBrightnessFilter class to adjust the brightness of an image. When theBrightnessFilter receives image data in the filterRGB method, it converts theRGB value into an HSB value using the Color class RGBtoHSB method. The filterthen adjusts the brightness components based on a specified factor, convertsthe colors back to the RGB format, and returns the new color. As shown inFigure 621, the applet creates a darker and a lighter version of the originalimage. A user can select which image to display using the selection buttons.
以下的小应用程序,brightness.java, 构造了一个BrightnessFilter 类来调正一幅图象的亮度. 当BrightnessFilter 在filterRGB方法中接受图象数据后, 就利用Color类的RGBtoHSB方法把RGB值转换为HSB值. 然后, 滤波器根据指定的比例因子来调整亮度分量, 再把色彩转换回RGB格式, 并把新的色彩返回调用者. 如图 621 所示, 小应用程序创建了一幅比原始图象亮的图象和一幅原始图象暗的图象. 用户可以利用选择按钮来选择显示哪一种图象.
import java.applet.*;
import java.awt.*;
importjava.awt.image.*;
class BrightnessFilterextends RGBImageFilter {
float adjustment;
float hsb_value[] = new float[3];
ColorModel dcm = ColorModel.getRGBdefault();// Default color model
public BrightnessFilter(float adjustment)
{
canFilterIndexColorModel = true;
this.adjustment = adjustment;
}
public int filterRGB (int x, int y, int rgb)
{
int a = rgb & 0xFF000000;
int pixcolor = rgb & 0x00FFFFFF;
Color.RGBtoHSB (dcm.getRed(rgb),dcm.getGreen(rgb),
dcm.getBlue(rgb),hsb_value);
hsb_value[2] *= adjustment;
hsb_value[2] = Math.max(0.0f, Math.min(hsb_value[2], 1.0f));
return (a | Color.HSBtoRGB(hsb_value[0],hsb_value[1],
hsb_value[2]));
}
}
public classbrightness extends Applet {
Image img, img_dark, img_light;
int selection = 0;
public void init()
{
ImageFilter lightf = new BrightnessFilter(1.25f);
ImageFilter darkf = newBrightnessFilter(0.50f);
img = getImage (getCodeBase(),"bgimg.jpg");
ImageProducer lproducer =
new FilteredImageSource(img.getSource(), lightf);
img_light = createImage (lproducer);
ImageProducer dproducer =
new FilteredImageSource(img.getSource(), darkf);
img_dark = createImage (dproducer);
setLayout (new BorderLayout());
Panel p = new Panel();
p.add (new Button ("Orig"));
p.add (new Button ("Light"));
p.add (new Button ("Dark"));
add ("South", p);
}
public boolean action(Event evt, Object arg)
{
if (evt.target instanceof Button)
{
if (arg.equals("Orig"))
selection = 0;
else if(arg.equals("Light"))
selection = 1;
else if(arg.equals("Dark"))
selection = 2;
repaint();
return true; // event processed
}
return false; // event not processed
}
public void paint(Graphics g)
{
switch (selection) {
case 0: g.drawImage (img, 0, 0, this);
break;
case 1: g.drawImage (img_light, 0, 0, this);
break;
case 2: g.drawImage (img_dark, 0, 0, this);
break;
}
}
}
Figure 621 Displaying an image using a brightnessfilter.
图621 利用亮度滤波器显示图象
622 Building a TransparentColor Filter Class
622 创建一个透明色彩滤波器类
In previous tips, you learned that you can use an image withtransparency by loading in a GIF file with transparent color. There may betimes when you want to convert an image without transparent color into one withtransparent color. To perform the conversion, you define a specific opaquecolor in the image to be transparent and use an RGBImageFilter to convert thiscolor into a transparent color. This is similar to the blue screen techniquespecial-effects people use in the movie industry. The following code,TransFilter.java, shows you how to build such a class. To specify thetransparent color, you can simply create the filter using the TransFilterconstructor with the specific color as an argument:
在以前的TIP中你已经知道,可以通过在GIF文件中装入透明色来使用带透明度的图象.你有时可能要把不带透明度的图象转换成带透明度的图象. 为了实行这种转换, 你可以为打算变成透明的图象定义一个专用的不透明的颜色, 并用RGBImageFilter将此颜色转换成一种透明的颜色. 这很象人们在电影工业中使用的蓝屏技术特技效果. 以下代码, TransFilter.java, 将向你说明怎样创建这样的类. 为了指定透明色, 你只要利用构造函数TransFilter来创建一个以指定颜色作为变元的滤波器:
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
public classTransFilter extends RGBImageFilter {
int transcolor;
public TransFilter(int transcolor)
{
canFilterIndexColorModel = true;
this.transcolor = transcolor;
}
public int filterRGB(int x, int y, int rgb)
{
int a = rgb & 0xFF000000;
int pixcolor = rgb & 0x00FFFFFF;
if (pixcolor == transcolor)
a = 0x00000000;
return (a | pixcolor);
}
}
623 Creating a Fade-InAnimation Special Effect
623 创建一个淡入式的动画特技效果
Tip xxx showed you how to switch from the display of one imageto another using a zoom-in effect. Another commonly-used special effect is thefade-in, which slowly transforms the pixels from the first image into those ofthe second image.
To implement a fade-in effect, you must normally create severalmerged versions of the two images with different ratios for each frame ofanimation. In Java, however, you can take advantage of the alpha transparencyfeature. You create a copy of the second image using a specific alpha(transparency) value. Then, you draw the first image and overlay it with thesemi-transparent version of the second image to create
the merged image. By repeating the process while increasing thealpha values for each frame of animation, you can create a fade-in animationeffect. The following applet, fade_in.java, implements the fade-in specialeffect. Figure 623 illustrates the applets output:
TIP XXX 向你展示了怎样利用zoom-in效果将图象的一种显示切换成另一种显示. 另有一种常用的特技效果叫作淡入,它把一幅图象中的象素颜色慢慢地变成为另一种颜色.通常,为了实现淡入效果, 你必须创建几幅图象来构成动画的帧, 每一帧图象都是由两幅图象利用不同的比例混合而成. 在Java中, 你可以利用alpha的透明属性方便. 你首先利用指定的alpha(透明)值创建第二幅图象的一个COPY. 然后, 把第一幅图象叠加画在第二幅图象的半透明版本上,来创建所需的混合图象. 通过不断增加alpha值来重复这一过程就可创建一系列能实现淡入效果的动画帧(画面). 以下的小应用程序,fade_in.java,实现了淡入特技效果. 图623是小应用程序的输出:
import java.applet.*;
import java.awt.*;
importjava.awt.image.*;
class FadeInFilterextends RGBImageFilter {
int transparency;
public FadeInFilter(int transparency)
{
canFilterIndexColorModel = true;
this.transparency = transparency;
}
public int filterRGB(int x, int y, int rgb)
{
int pixcolor = rgb & 0x00FFFFFF;
int a = (transparency << 24) &0xFF000000;
return (a | pixcolor);
}
}
public class fade_inextends Applet implements Runnable {
Image img1, img2, fg_img;
Image offscreen;
Thread anime = null;
public void init()
{
img1 = getImage (getCodeBase(),"turtoise.gif");
img2 = getImage (getCodeBase(),"sheepb.gif");
MediaTracker mt = newMediaTracker(this);
mt.addImage (img1, 1);
mt.addImage (img2, 1);
try {
mt.waitForAll();
}
catch (InterruptedException e) {};
fg_img = img2;
}
public void update (Graphics g)
{
paint(g);
}
public void paint(Graphics g)
{
// prepare offscreen image
Graphics goff = offscreen.getGraphics();
goff.drawImage (img2, 0, 0, this);
goff.drawImage (fg_img, 0, 0, this);
// copy offscreen to onscreen
g.drawImage (offscreen, 0, 0, this);
goff.dispose();
}
public void run()
{
while (anime != null)
{
// fade In
for (int i = 0; i < 256; i+= 32)
{
ImageFilter f = newFadeInFilter(i);
ImageProducer producer =
newFilteredImageSource(img1.getSource(), f);
fg_img = createImage (producer);
// wait until new image isready
MediaTracker mt = newMediaTracker(this);
mt.addImage (fg_img, 1);
try {
mt.waitForID(1);
}
catch (InterruptedException e){};
repaint ();
try {
Thread.sleep (500);
}
catch (InterruptedException e){};
fg_img.flush();
}
// fade Out
for (int i = 255; i > 0; i -= 32)
{
ImageFilter f = newFadeInFilter(i);
ImageProducer producer =
new FilteredImageSource(img1.getSource(), f);
fg_img = createImage (producer);
// wait until new image is ready
MediaTracker mt = newMediaTracker(this);
mt.addImage (fg_img, 1);
try {
mt.waitForID(1);
}
catch (InterruptedException e){};
repaint();
try {
Thread.sleep (500);
}
catch (InterruptedException e){};
fg_img.flush();
}
}
}
public void start()
{
if (anime == null)
{
anime = new Thread(this);
anime.start();
}
offscreen = createImage (size().width,size().height);
}
}
Production: Insert figure from jtp0033.bmp [MCC]
Figure 623 Displaying images using a fade-inspecial effect.
图623 淡入特技效果图象的显示
624 Creating Your Own ImageFilter
624 创建你自己的图象滤波器
As you have learned, the RGBImageFilter class lets you build animage filter that calculates a pixels new color based solely on the pixelscurrent color value and position. However, if you want to create a filter thatcan process a pixels color value based on the color values of other pixels(such as surrounding pixels), you must create your own ImageFilter class.Tocreate your own ImageFilter class, you must first create a class that extendsImageFilter class. Then, you will have to override some of the followingImageConsumer methods:
你已知道利用RGBImageFilter类可以创建一个图象滤波器, 这种滤波器在计算每个象素点的色彩值时, 只根据象素当前点的色彩值和位置. 但如果你想创建一个能根据其它象素(如周围的象素)的色彩值来计算象素色彩值的图象滤波器, 你就必须创建你自己的ImageFilter类. 为了创建ImageFilter类,你必须首先创建一个类来扩展ImageFilter类.
然后, 你必须利用下列的某个ImageConsumer 方法:
. The ImageFilter class uses the setDimensions method to reportthe dimension of the image. You canoverride this method to find the size of the source image and to specify the size of the outputimage if it differs from the source.
. ImageFilter 类利用 setDimensions 方法来报告图象的大小. 你可利用这一方法来找出源图象的大小, 并在输出图象的尺寸与它不同时来指定输出图象的的大小.
. The image producer calls the setColorModel method to specifythe color model of the source image.
. 图象生成器调用setColorModel 方法来指定源图象的色彩模式.
. The image producer calls the setHint method to specify theorder in which the image producerdelivers the pixel data.
. 图象生成器调用setHint方法来指定提交图象数据的次序(order).
. The image producer calls the setProperties method if it needsto send a list of properties associated with the source image.
. 图象生成器如果对源图象有关属性需要发送一个清单时则调用setProperties方法.
. The image producer calls the setPixels method one or moretimes to send the images pixel data. You will normally override this method ifyou are processing any pixel data.
. 图象生成器一次或多次调用setpixel方法来发送图象的象素值数据. 如果你是在处理 象素数据, 则你通常总是利用这一方法.
. When the image producer finishes sending pixel data to thesetPixels methods, it calls the imageComplete method to let the consumer knowthat the image is complete.
. 当图象生成器结束了向setPixel方法发送象素数据,它调用imageComplete 方法使图形用户知道图象已完成了.
If you override any of the above methods, be sure to call theconsumers methods yourself to pass the filtered information along to the imageconsumer.
如果你利用以上任何一种方法, 你必须自己调用consumers方法, 把滤波信息传递给图象用户.
625Sharpening an Image
625图象的清晰化
When your applet works with images, you can use area processingto sharpen an image, detect edges, or remove noise. To sharpen an image, youcan apply an image processing algorithm known as convolution. Put simply, aconvolution operation calculates the color value of a pixel based on theweighted sum of the color values of its neighboring pixels. The followingequation shows you how the convolution algorithm calculates the color value ofa pixel :
当你的小应用程序带图象工作时,你可以利用图象处理使图象清晰化,检测其边界,或消除噪声,等. 为了使图象清晰化, 你可使用称作卷积(convolution)的一种图象处理算法. 简单地说,卷积操作就是根据邻近象素点的色彩值的权和(weighted sum)来计算本点的色彩值. 以下方程告诉你怎样对一个象素点的色彩值进行卷积计算:
P (x, y) = ( W(w, h) *P(x + w, y + h);
W is the matrix that stores the pixel weights. The variable wgoes from 0 to the width of the weights matrix minus one, and h goes from 0 tothe height of the weights matrix minus one. The following applet,sharp_filter.java, implements an image-sharpening filter. The applet displaysthe original image at the top and the sharpened image at the bottom, as shownin Figure 625:
其中, W是存放象素权值的矩阵. 变量 w 从0变到权矩阵的宽度减1, h从0变到权矩阵的高度减1. 以下的小应用程序sharp_filter.java实现了图象清晰化滤波. 小应用程序把原始图象显示在上边, 而清晰化后的显示在下边, 如图625所示:
import java.applet.*;
import java.awt.*;
importjava.awt.image.*;
class SharpenFilterextends ImageFilter {
int source_img[];
int dest_width, dest_height;
int source_width, source_height;
ColorModel ocm; // output color model
// sharpen convolution kernel
int filter_weight[] = {-1,-1,-1,-1,9,-1,-1,-1,-1};
public void setDimensions(int width, intheight)
{
source_img = new int[width * height];
source_width = width;
source_height = height;
dest_width = width - 2;
dest_height = height - 2;
consumer.setDimensions(dest_width, dest_height);
}
public void setColorModel(ColorModel model)
{
ocm = ColorModel.getRGBdefault();
consumer.setColorModel(ocm);
}
public void setPixels(int x, int y, int w,int h,
ColorModel model, byte pixels[], int off,int scansize)
{
int srcoff = off;
int dstoff = y * source_width + x;
for (int yi = 0; yi < h; yi++)
{
for (int xi = 0; xi < w; xi++)
{
source_img[dstoff] =model.getRGB(pixels[srcoff++] &
0xff);
source_img[dstoff++] =model.getRGB(pixels[srcoff++] &
0xff);
}
srcoff += (scansize - w);
dstoff += (source_width - w);
}
}
public void setPixels(int x, int y, int w,int h,
ColorModel model, int pixels[], int off,int scansize)
{
int srcoff = off;
int dstoff = y * source_width + x;
for (int yi = 0; yi < h; yi++)
{
for (int xi = 0; xi < w; xi++)
source_img[dstoff++] =model.getRGB(pixels[srcoff++]);
srcoff += (scansize - w);
dstoff += (source_width - w);
}
}
public void imageComplete(int status)
{
int sr, sg, sb;
int tr, tg, tb, ta;
if(status == IMAGEERROR || status == IMAGEABORTED)
{
consumer.imageComplete(status);
return;
}
// create output image
int dest_img[] = new int[dest_width]; //storage for one line
for (int yi = 0; yi < dest_height;yi++)
{
for (int xi = 0; xi < dest_width;xi++)
{
tr = tg = tb = 0;
for (int ky=0; ky<3; ky++)
{
for (int kx=0; kx<3;kx++)
{
int rgb =source_img[(yi+ky) *
source_width+xi+kx];
sr = ocm.getRed (rgb);
sg = ocm.getGreen (rgb);
sb = ocm.getBlue (rgb);
tr += sr *filter_weight[ky*3+kx];
tg += sg *filter_weight[ky*3+kx];
tb += sb *filter_weight[ky*3+kx];
}
}
tr = Math.max(0, Math.min (tr,255));
tg = Math.max(0, Math.min (tg,255));
tb = Math.max(0, Math.min (tb,255));
dest_img [xi] = 0xFF000000 | (tr<< 16) |
(tg << 8)| tb;
}
consumer.setPixels(0, yi,dest_width, 1, ocm, dest_img,
0, dest_width);
}
dest_img = null;
consumer.imageComplete(status);
}
}
public classsharp_filter extends Applet {
Image orig_img, sharpened_img;
public void init()
{
ImageFilter f = new SharpenFilter();
orig_img = getImage (getCodeBase(),"tiger.jpg");
ImageProducer producer =
new FilteredImageSource(orig_img.getSource(), f);
sharpened_img = createImage (producer);
}
public void paint(Graphics g)
{
g.drawImage (orig_img, 0, 0, this);
g.drawImage (sharpened_img, 0, 200,this);
}
}
Figure 625 Using a filter to sharpen an image.
图625 用滤波器来锐化一图像
1001 Java Programming Tips
Page
PAGE
10
of
numpages
18
filename
jtipmeda.doc
TIME \@ "MMMM d, yyyy"
September 12, 1996