第 9章 Java在多媒体中的应用
第 9章 Java在多媒体中的应用
9.1 利用 AWT绘图
9.2 Graphics类的使用
9.3 Font类的使用
9.4 图像处理
9.5 动画图像处理
第 9章 Java在多媒体中的应用
9.1 利用 AWT绘图
这一节中我们主要介绍如何使用 Java语言提供的
AWT包绘图。 java.awt包中提供了用于绘图的 API,我
们通常称之为 2D API。不要以为只有设计绘图程序或
游戏软件才会用到 Java 2D,其实 Java 2D的用途可能远
比你想象的更广泛。
第 9章 Java在多媒体中的应用
其实, 只要你的程序有 GUI,就很可能会用到 Java 2D。
因为 AWT和 Swing的组件常常无法完全适合我们, 这
个时候自己绘制一部分的 GUI就有绝对的必要 。 甚至,
我们还可以用 Java 2D来绘制自己的组件 。 实际上,
AWT和 Swing组件都是透过 Java 2D来进行绘制的 。
第 9章 Java在多媒体中的应用
Java 2D API增强了 AWT的图形, 文本和图像功能,
可以开发更为强大的用户接口和新型的 Java应用程序 。
除了更为强大的图形, 字体和图像 API外, Java 2D API
还改进了颜色的定义与复合及对任意几何形状和文本
的选中检测, 并为打印机和显示设备提供了统一的绘
制模式 。 Java 2D API还可以创建高级图形库, 并可创
建图像和图形文件读 /写过滤器 。 当与 Java媒体框架
(JMF) 和其他 Java媒体应用程序配合使用时, Java 2D
API还可用来创建和显示动画和其他多媒体演示稿 。
第 9章 Java在多媒体中的应用
到底 Java 2D API有多强大? 这一点我们可以通过
SUN JDK包中提供的例程来了解 。 在命令行窗口下输
入:
c:\>cd \jdk1.2\demo\jfc\Java2D
c:\jdk1.2\demo\jfc\Java2D>java
-classpath Java2Demo.jar Java2Demo

c:\jdk1.2\demo\jfc\Java2D>appletviewer
java2demo.html
看到了吗? Java 2D神奇的威力 !
第 9章 Java在多媒体中的应用
下面我们来学习如何使用 Java 2D绘图 。 上面看到
的例子虽然功能十分强大, 但是它的实现非常复杂 。
下面, 我们先从简单一点的入手 。
从 java.awt.Component类 (所有窗口对象的基类 )继
承的类提供了一个名为 paint()的方法, 在需要重新绘制
组件时, 可调用该方法 。
paint()方法只有一个参数, 该参数是 Graphics类的
实例 。 如果在某个继承了 Component的类中覆盖了该方
法, 那么就可以使用该方法来控制在控制区域着何种
颜色 。 例如, 下面的类创建了一个带有蓝背景的面板 。
第 9章 Java在多媒体中的应用
例 9.1 BluePanel.java
import java.awt.*;
class BluePanel extends Panel
{ public static void main(String[] args)
{ Frame f = new Frame();
BluePanel p = new BluePanel();
f.add(p);
f.setSize(300,100);
f.setVisible(true);}
第 9章 Java在多媒体中的应用
// Invoked when the panel needs to be repainted
public void paint(Graphics g)
{ // Get the rectangle that represents the viewable area
// of the panel
Rectangle rect = g.getClipBounds();
// Set the context to paint in a pre-defined color
g.setColor(Color.blue);
// Fill the rectangle with the current color
g.fillRect(rect.x,rect.y,rect.width,rect.height);}
} 程序运行结果如图 9.1所示 。
第 9章 Java在多媒体中的应用
图 9.1
第 9章 Java在多媒体中的应用
9.2 Graphics类的使用
java.awt中提供了一系列的类用于绘制图形。其中,
Color类包含了编辑颜色的方法和常量; Font类包含了
编辑字体的方法和常量; FontMetrics类包含了获取字
体信息的方法; Polygon类包含了创建多边形的方法;
Toolkit类提供了从系统获得图形信息的方法,例如可
显示的字体集和屏幕分辨率等等; Graphics类包含了绘
制字符串、线条以及各种几何图形的方法。
第 9章 Java在多媒体中的应用
Graphics是一个抽象类, 其作用是定义一个真正的
工具, 用来接受图形操作 。 在该类中, 有 47个公用方
法, 可以用作显示图像和文本, 绘制和填充形状, 剪
贴图像操作等等 。
9.2.1 绘制字符串, 字符和字节
用于绘制字符串, 字符和字节的方法分别为
● public abstract void drawString(String string,int x,int
y)在坐标 (x,y)处以当前字体和颜色绘制指定的字符串
string。
第 9章 Java在多媒体中的应用
● public void drawChars(char[] chars,int offset,int
number,int x,int y)
在坐标 (x,y)处以当前字体和颜色绘制指定的一系
列字符 。 chars为要绘制的字符组, offset为位置的坐标,
number为要绘制的元素个数 。
● public void drawBytes(byte[] bytes,int offset,int
number,int x,int y)
在坐标 (x,y)处以当前字体和颜色绘制指定的一系
列字节 。 bytes为要绘制的字节数组, offset为位置的坐
标, number为要绘制的元素个数 。
第 9章 Java在多媒体中的应用
下面的例子展示了如何使用了 drawString(),
drawChars()和 drawBytes()三个方法:
例 9.2 DrawSCB.java
import java.awt.*;
public class DrawSCB extends Frame
{ String s = "Using drawString!";
char[] c = {'c','h','a','r','s',' ','8'};
byte[] b = {'b','y','t','e',1,2,3};
第 9章 Java在多媒体中的应用
public static void main(String[] args)
{ DrawSCB frame = new DrawSCB();
frame.setSize(300,100);
frame.setVisible(true); }
public void paint(Graphics g)
{ g.drawString(s,100,40);
g.drawChars(c,0,7,100,65);
g.drawBytes(b,0,5,100,90);}
}
程序运行结果如图 9.2所示 。
第 9章 Java在多媒体中的应用
图 9.2
第 9章 Java在多媒体中的应用
9.2.2 颜色控制
Color类定义了颜色常量和方法。每种颜色都是从
RGB(红 /绿 /蓝 )值创建出来的。一个 RGB值有三部分,
都是从 0~255的整数值,分别代表着三种颜色的含量。
因此,实际上我们可以使用 256× 256× 256种颜色,即
224种颜色。这就是我们常说的 24位真彩色。但不是任
何计算机都可以显示所有的颜色,就目前来说,大部
分计算机都可以显示 24位甚至超过 24位的彩色。显然,
我们很难记住一种颜色的 RGB值,因而,Color类将一
些最常用的颜色预定义为常量以方便我们使用。表 9.1
列出了预定义的颜色常量。
第 9章 Java在多媒体中的应用
表 9.1 Color类中定义的颜色常量
颜色常量 颜色 RGB值
public final static Color orange 橙色 255,200,0
public final static Color pink 粉红色 255,175,175
public final static Color cyan 青色 0,255,255
public final static Color magenta 火红色 255,0,255
public final static Color yellow 黄色 255,255,0
public final static Color black 黑色 0,0,0
public final static Color white 白色 255,255,255
第 9章 Java在多媒体中的应用
public final static Color gray 灰色 128,128,128
public final static Color lightGray 浅灰色 192,192,192
public final static Color darkGray 深灰色 64,64,64
public final static Color red 红色 255,0,0
public final static Color green 绿色 0,255,0
public final static Color blue 蓝色 0,0,255
第 9章 Java在多媒体中的应用
Color类中常用的一些方法如下:
● public Color(int r,int g,int b):创建指定 RGB值的颜色 。
● public int getRed():返回红色含量的值 。
● public int getBlue():返回蓝色含量的值 。
● public int getGreen():返回绿色含量的值 。
Graphics类与 Color类相关的常用方法有:
● public abstact Color getColor():返回图形上下文的当
前颜色 。
● public abstract void setColor(Color c):设置图形上下文
的当前颜色 。
第 9章 Java在多媒体中的应用
下面来看一个颜色控制的实例 。
例 9.3 ShowColor.java
import java.awt.*;
public class ShowColor extends Frame
{ int red,green,blue;
public static void main(String[] args)
{ ShowColor frame = new ShowColor();
frame.setSize(300,100);
frame.setVisible(true); }
public ShowColor()
第 9章 Java在多媒体中的应用
{ red = 200;
green = 100;
blue = 0; }
public void paint(Graphics g)
{ g.setColor(new Color(red,green,blue));
g.drawString("Draw color string.",50,40);
Color color = g.getColor();
第 9章 Java在多媒体中的应用
g.drawString("Red:"+color.getRed(),10,70);
g.drawString("Green:"+color.getGreen(),100,70);
g.drawString("Blue:"+color.getBlue(),200,70); }
}
程序运行结果如图 9.3所示 。
第 9章 Java在多媒体中的应用
图 9.3
第 9章 Java在多媒体中的应用
9.2.3 绘制几何图形
Graphics类中用于绘制几何图形的方法如下:
● public abstract void drawLine(int x1,int y1,int x2,int
y2)
在点 (x1,y1)和 (x2,y2)之间用当前颜色绘制线段 。
● public void drawRect(int x,int y,int width,int height)
以点 (x,y)为左上角坐标, width和 height为宽度和
高度, 用当前颜色画矩形 。
● public abstact void fillRect(int x,int y,int width,int
height)
第 9章 Java在多媒体中的应用
以点 (x,y)为左上角坐标, width和 height为宽度和
高度, 用当前颜色画一个实心的矩形 。
● public abstact void clearRect(int x,int y,int width,int
height)
以点 (x,y)为左上角坐标, width和 height为宽度和高
度, 用当前背景颜色画一个实心的矩形 。 此方法用于
清除某个矩形显示区域 。
● public abstact void drawRoundRect(int x,int y,int
width,int height,int arcWidth,int arcHeight)
以点 (x,y)为左上角坐标, width和 height为宽度和高
度, 用当前颜色画圆角矩形 。
第 9章 Java在多媒体中的应用
● public abstact void fillRoundRect(int x,int y,int width,
int height,int arcWidth,int arcHeight)
以点 (x,y)为左上角坐标, width和 height为宽度和高
度, 用当前颜色画一个实心的圆角矩形 。
● public void draw3Drect(int x,int y,int width,int height,
boolean b)
用指定的 width和 height,以当前颜色画一个三维矩
形 。 矩形的左上角坐标为 (x,y)。 当 b为 true时, 矩形为
凸的; b为 false时, 矩形为凹的 。
第 9章 Java在多媒体中的应用
● public void fill3Drect(int x,int y,int width,int height,
boolean b)
用指定的 width和 height,以当前颜色画一个填充的三
维矩形 。 矩形的左上角坐标为 (x,y)。 当 b为 true时, 矩形
为凸的; b为 false时, 矩形为凹的 。
● public abstract void drawOval(int x,int y,int width,int
height)
用指定的 width和 height,以当前颜色画椭圆 。 外切矩
形的左上角坐标为 (x,y)。
● public abstract void fillOval(int x,int y,int width,int
height)
用指定的 width和 height,以当前颜色画实心椭圆。外
切矩形的左上角坐标为 (x,y)。
第 9章 Java在多媒体中的应用
● public abstract void drawArc(int x,int y,int width,int
height,int startAngle,int arcAngle)
参考外切矩形的左上角坐标 (x,y),用指定的 width
和 height,以当前颜色绘制一段弧 。 弧段从起始角
startAngle开始一直到张角 arcAngle。
● public abstract void fillArc(int x,int y,int width,int
height,int startAngle,int arcAngle)
参考外切矩形的左上角坐标 (x,y),用指定的 width
和 height,以当前颜色绘制一段实心的弧 。 弧段从起始
角 startAngle开始一直到张角 arcAngle。
第 9章 Java在多媒体中的应用
● public abstract void drawPolygon(int[] xPoints,int[]
yPoints,int points)
以当前颜色画一个具有 points个顶点的多边形 。
xPoint和 yPoint数组分别指定了每个顶点的 x和 y坐标 。
● public void drawPolygon(Polygon p)
以当前颜色画指定的多边形 。
第 9章 Java在多媒体中的应用
● public abstract void fillPolygon(int[] xPoints,int[],
yPoints,int points)
以当前颜色画一个具有 points个顶点的填充多边形 。
xPoint和 yPoint数组分别指定了每个顶点的 x和 y坐标 。
下面我们通过一个例子来学习这些方法 。
第 9章 Java在多媒体中的应用
例 9.4 DrawDemo.java
import java.awt.*;
public class DrawDemo extends Frame
{ public static void main(String[] args)
{ DrawDemo frame = new DrawDemo();
frame.setSize(400,500);
frame.setVisible(true); }
public void paint(Graphics g)
第 9章 Java在多媒体中的应用
{ // draw a line
g.drawLine(10,30,200,40);
// draw a rectangle
g.drawRect(10,50,100,50);
// draw a filled rectangle
g.fillRect(150,50,100,50);
// draw a rounded rectangle
g.drawRoundRect(10,120,50,50,10,20);
// draw a filled rounded rectangle
g.fillRoundRect(80,120,50,50,40,20);
// draw a ellipse
第 9章 Java在多媒体中的应用
g.drawRoundRect(150,130,80,20,70,70);
// draw a filled square
g.drawRoundRect(250,120,50,50,0,0);
// draw a circle
g.drawRoundRect(330,120,50,50,50,50);
g.setColor(Color.yellow);
// draw a raised 3D rectangle
g.draw3DRect(10,190,50,50,true);
// draw a sunk 3D rectangle
g.draw3DRect(100,190,50,50,false);
第 9章 Java在多媒体中的应用
// draw a filled raised 3D rectangle
g.fill3DRect(200,190,50,50,true);
// draw a filled sunk 3D rectangle
g.fill3DRect(300,190,50,50,false);
g.setColor(Color.black);
// draw an oval
g.drawOval(10,260,70,50);
// draw an filled oval
g.fillOval(200,260,50,70);
// draw an arc
g.drawArc(10,350,60,60,0,180);
第 9章 Java在多媒体中的应用
// draw solid arc
g.fillArc(100,350,50,60,0,270);
g.fillArc(200,350,50,60,0,-110);
g.fillArc(300,350,40,60,0,-360);
// draw a polygon
int[] xPoints1 = {10,30,40,20,10,5,10};
int[] yPoints1 = {430,430,440,460,460,440,430};
g.drawPolygon(xPoints1,yPoints1,7);
第 9章 Java在多媒体中的应用
// draw a filled polygon
int[] xPoints2 = {100,120,130,110,100,95,90,100};
int[] yPoints2 = {430,430,440,460,460,440,420,430};
g.fillPolygon(xPoints2,yPoints2,8); }
}
程序运行结果如图 9.4所示 。
第 9章 Java在多媒体中的应用
图 9.4
第 9章 Java在多媒体中的应用
9.2.4 屏幕操作
本节介绍一种实现屏幕操作的 Graphics方法
copyArea()。 copyArea()方法用于复制屏幕的一个区域,
并将它放置在屏幕的另一个位置上。 copyArea方法的
定义如下,public abstract void copyArea(int x,int y,int
width,int height,int dx,int dy)其中,参数 x和 y指定了复
制区域的左上角坐标; width和 height为区域的宽和高;
dx和 dy指定了与点 (x,y)的水平和垂直偏移量,复制的
区域放置在该偏移量相对于 (x,y)的位置上。
第 9章 Java在多媒体中的应用
例 9.5 CopyAreaDemo.java
import java.awt.*;
public class CopyAreaDemo extends Frame
{ public static void main(String[] args)
{ CopyAreaDemo frame = new CopyAreaDemo();
frame.setSize(300,200);
frame.setVisible(true); }
public void paint(Graphics g)
第 9章 Java在多媒体中的应用
{ g.drawRect(20,30,50,50);
g.fillOval(50,100,50,70);
g.copyArea(20,30,100,170,150,20);}
}
程序运行结果如图 9.5所示 。
第 9章 Java在多媒体中的应用
图 9.5
第 9章 Java在多媒体中的应用
9.2.5 绘图模式
绘图模式 (paint mode)用于描述如何绘图 。 默认的
绘图模式是覆盖模式 (overwrite),当一个图形画在另一
个图形上面时, 旧的图形将被覆盖, 看到的将只是新
的图形 。 另外, 还有一种异或绘图模式 (XOR),使用
这种模式可以看到互相重叠的所有图形 。 使用异或绘
图模式可以通过调用 Graphics的方法:
public abstract void setXORMode(Color c)
第 9章 Java在多媒体中的应用
来实现 。 该方法的参数为一个 Color对象 。 这个颜色称
作 XORMode颜色 。 由于 XOR绘图模式实际上是对新旧
两种颜色的二进制值做异或操作, 所以当重叠的部分
颜色相同时, 将恢复为背景颜色 。 这时候可以通过设
置 XORMode颜色, 指定用某颜色来替代 。 例如:
例 9.6 XORModeDemo.java
import java.awt.*;
public class XORModeDemo extends Frame
{ public static void main(String[] args)
{ XORModeDemo frame = new XORModeDemo();
第 9章 Java在多媒体中的应用
frame.setSize(300,100);
frame.setVisible(true); }
public void paint(Graphics g)
{ // draw a pink oval
g.setColor(Color.pink);
g.fillOval(20,30,100,50);
// draw a yellow rectangle over part of the oval
g.setColor(Color.yellow);
g.fillRect(100,30,100,50);
// draw an orange rectangle
g.setColor(Color.orange);
第 9章 Java在多媒体中的应用
g.fillOval(190,30,80,50);
// set XOR mode to yellow
g.setXORMode(Color.yellow);
g.fillOval(180,45,60,20);
// draw a blue arc
g.setColor(Color.blue);
g.fillArc(150,40,20,20,0,360);
// draw a red square
g.setColor(Color.red);
g.fillRect(120,45,20,20);}
}
第 9章 Java在多媒体中的应用
程序绘制了六种不同的形状, 前三种为覆盖模式,
后三种为异或模式 。 大家可以通过运行结果中图形重
叠部分看出两种不同绘图模式的效果 。 程序运行结果
如图 9.6所示 。
第 9章 Java在多媒体中的应用
图 9.6
第 9章 Java在多媒体中的应用
9.3 Font类的使用
Java 2D具有复杂文本的输出能力 。 Java 2D和一个
重新设计的字体引擎支持使用属性集对字符串的单个
字符进行操作 。
9.3.1 字体
字体是一套具有一个点尺寸和外观的字符类型集
合,例如,所有 10点 Helvetica英文字符和符号组成一
个字体。文本所使用的字体定义特定的外观、大小和
式样 (黑体、斜体或者普通体 )。
第 9章 Java在多媒体中的应用
字体如何定义特定外观呢? 字体是从字形 (glyphs)
创建的, 一个字形是一个位映像图像, 它定义字体中
的字符和符号的外观 。 同一字体家族的字体都有相似
的外观, 因为他们使用同一个字形创建 。 同样的, 不
同的字体家族使用不同的字形得到相互区分的外观 。
一个字体家族不但由具有相似外观的字体组成,
还包括不同的大小和式样 。 Helvetica 10 point黑体和
Helvetica 12 point斜体是同一家族中的两个不同字体,
而 Times Roman 8 point黑体和 Times Roman 10 point普
通体是另一个家族的两个不同字体 。
第 9章 Java在多媒体中的应用
为了使用一个字体, 需要创建一个 Font对象, 而
为了做到这个, 则需要知道系统中有什么字体可用以
及它们的名字 。 字体有逻辑名, 家族名和字体名 。
逻辑名是被映射到平台上, 可用的特定字体的名
字 。 调用 java.awt.Font.getName类可以得到一个 Font对
象的逻辑名 。
第 9章 Java在多媒体中的应用
家族名是字体家族的名字,它通过不同的外观决
定排版图案,例如,Helvetica或者 Times New Roman。
要得到一个 Font对象的家族名,须调用
java.awt.Font.getFamily类。
字体名代表家族中的特定字体,例如 Helvetica
Bold。要得到一个 Font对象的字体名,须调用
java.awt.Font.getFontName类。要决定系统上哪些字体
可用,须调用
java.awt.GraphicsEnvironment.getAllFonts类。
第 9章 Java在多媒体中的应用
9.3.2 创建和派生字体
创建一个字体的最简单的方法是指定字体名、大小
和式样。一旦你有一个 Font对象,你就可以通过调用
Font.deriveFont方法在存在的字体上派生任意个新 Font对
象,并指定新的大小、样式、变换 (位置、倾斜、缩放或
者旋转 )或者属性映射。例如
Font boldFont = new Font("Helvetica",Font.BOLD,12);
Font italicDerived = boldFont.deriveFont(Font.ITALIC,12);
Font plainDerived = boldFont.deriveFont(Font.PLAIN,14);
第 9章 Java在多媒体中的应用
一旦你有一个字体,你就可以用它创建一个
TextLayout对象并绘制艺术字。
java.awt.Font.TextLayout类可以让你使用字符、字体和
属性集创建艺术字。一旦被创建,TextLayout对象就不
可编辑,但是它的方法可以让你访问布局、字体、脱
字符,选择和点击测试信息。
下面的代码使用 Font,TextLayout和
FontRenderContext 对象绘制了一个简单的文本,使用
的是 24 point Times黑体。
第 9章 Java在多媒体中的应用
例 9.7 TimesB.java
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.Font.*;
public class TimesB extends Canvas
{ private Image img;
publicc TimesB()
{setBackground(Color.white); }
public void paint(Graphics g)
第 9章 Java在多媒体中的应用
{ Graphics2D g2;
g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
ontRenderContext frc = g2.getFontRenderContext();
Font f = new Font("Times",Font.BOLD,24);
String s = new String("24 Point Times Bold");
TextLayout tl = new TextLayout(s,f,frc);
Dimension theSize= getSize();
第 9章 Java在多媒体中的应用
g2.setColor(Color.green);
tl.draw(g2,theSize.width/30,theSize.height/2); }
public static void main(String s[])
{ WindowListener l = new WindowAdapter()
{public void windowClosing(WindowEvent e)
{System.exit(0);}
public void windowClosed(WindowEvent e)
{System.exit(0);}
};
第 9章 Java在多媒体中的应用
Frame f = new Frame("2D Text");
f.addWindowListener(l);
f.add("Center",new TimesB());
f.pack();
f.setSize(new Dimension(400,300));
f.show(); }
}
程序运行结果如图 9.7所示 。
第 9章 Java在多媒体中的应用
图 9.7
第 9章 Java在多媒体中的应用
程序中,java.awt.Font代表系统中可用字体的一个
实例; java.awt.TextLayout代表不可变的艺术字数据;
java.awt.Font.FontRenderContext包含绘制文本时需要的
正确测量和定位的信息。
第 9章 Java在多媒体中的应用
9.4 图 像 处 理
正如上一节所介绍的,Graphics类中确实提供了不
少绘制图形的方法,但如果用它们在 Applet运行过程中
实时地绘制一幅较复杂的图形,就好比是在用斧头和
木块去制造航天飞机。因此,对于复杂图形,一般都
事先用专用的绘图软件将其绘制好,或者是用其他截
取图像的工具 (如扫描仪、视效卡等 )获取图像的数据信
息,再将它们按一定的格式存入图像文件中。程序运
行时,只要找到图像文件存贮的位置,将它装载到内
存里,然后在适当的时机将它显示在屏幕上就可以了。
第 9章 Java在多媒体中的应用
9.4.1 加载和显示图像
在 AWT中,java.awt.image类用于描述图像,它通
过传递一个 Image类对象的引用给
Graphics.drawImage(Image,int,int,ImageObserver)方法,
就可以将图像在画布 (Canvas)或是其他可视组件中显示
出来。
第 9章 Java在多媒体中的应用
Java目前所支持的图像文件格式只有两种, 分别是
GIF和 JPEG格式 (带有,GIF,.JPG,.JPEG后缀名的文
件 )。 因此, 若图像文件是其他格式, 就须先将它们转
换为这两种格式 。
java.awt.image是一个抽象类, 它定义的方法提供
对图像信息的访问 。 下面通过一个例子来看看如何利
用 Image类来显示一幅图像 。
第 9章 Java在多媒体中的应用
例 9.8 ImageTestApplication.java
import java.awt.*;
import java.awt.event.*;
public class ImageTestApplication extends Frame {
Insets insets;
Image im;
static public void main(String args[]) {
ImageTestApplication app = new ImageTestApplication();
第 9章 Java在多媒体中的应用
app.show(); }
public ImageTestApplication() {
super("Image Test");
im = Toolkit.getDefaultToolkit().getImage("tiger.gif");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent event)
{
dispose();
System.exit(0);}
});
}
第 9章 Java在多媒体中的应用
public void addNotify() {
super.addNotify(); // peer is created here
insets = getInsets();
setBounds(100,100,217 + insets.left,321 +
insets.top); }
public void paint(Graphics g) {
g.drawImage(im,insets.left,insets.top,this);
System.out.println("drawing image...");
System.out.println(g.drawImage(im,insets.left,
insets.top,this)); }
}
第 9章 Java在多媒体中的应用
在应用程序中加载图像必须调用 Toolkit类的静态
方法 getImage(),该方法返回一个指定图像文件的
Image对象描述,然后在 paint()方法中调用 Graphics类的
drawImage()方法,就可以将图片显示在当前容器中。
第 9章 Java在多媒体中的应用
需要注意的是 addNotify()方法, 覆盖这个方法是为
了得到框架窗口空白区域的引用, 并用它来设置框架
窗口的大小 。 这样做是因为框架窗口的左上角 (0,0)坐
标是从标题栏开始计算的, 如果将图从 (0,0)开始画,
空白区域以外 (即标题栏覆盖的部分 )将会被裁减, 所以
必须从坐标 (insets.left,insets.top)的位置开始画图 。 程
序的运行结果如图 9.8所示 。
第 9章 Java在多媒体中的应用
图 9.8
第 9章 Java在多媒体中的应用
在上面的例子中, 查看控制台会发现, paint()方法
被调用了很多次, 这是因为 getImage()方法是启动一个
线程来加载图像的, 所以 paint()方法被调用的时候不一
定已经载入了整张图片, 每次只绘出已经加载的部分 。
第 9章 Java在多媒体中的应用
Java这样采用线程的做法虽然会提高性能,但是也
为编程带来了一些问题。例如,上例中的 setBounds()
方法中的尺寸是硬编码 (直接写入数值 )的,这种方法缺
乏通用性,是明确不被推荐的做法。较好的方法是直
接取图像的尺寸,通过调用 Image.getWidth()和
Image.getHeight()方法可以做到。因为在图像被完全加
载以前,它们的返回值都是 -1,所以要等到图像加载
完才能调用它们。
第 9章 Java在多媒体中的应用
如何知道图像有没有被加载完呢? AWT包为此提
供了 MediaTracker类用于监控图像的加载过程 。 使用
MediaTracker类分为三步:
(1) 创建 MediaTracker对象 。
(2) 使用 MediaTracker.addImage()指明要监控的图
像对象 。
(3) 创建 try/catch块, 等待和指定与 ID相关的图像
被完全加载 。
现在采用 MediaTracker类来改写上面的例子 。
第 9章 Java在多媒体中的应用
例 9.9 ImageTestApplication.java
import java.awt.*;
import java.awt.event.*;
public class ImageTestApplication extends Frame {
Insets insets;
Image im;
int width,height;
static public void main(String args[]) {
ImageTestApplication app = new
ImageTestApplication();
第 9章 Java在多媒体中的应用
app.show(); }
public ImageTestApplication() {
super("Image Test");
MediaTracker tracker = new MediaTracker(this);
im = Toolkit.getDefaultToolkit().getImage("tiger.gif");
tracker.addImage(im,0);
try { tracker.waitForID(0); }
catch (InterruptedException e) {
e.printStackTrace(); }
width = im.getWidth(this);
height = im.getHeight(this);
第 9章 Java在多媒体中的应用
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent event)
{
dispose();
System.exit(0);}
});
}
public void addNotify() {
super.addNotify(); // peer is created here
insets = getInsets();
setBounds(100,100,width + insets.left,height +
insets.top); }
第 9章 Java在多媒体中的应用
public void paint(Graphics g) {
g.drawImage(im,insets.left,insets.top,this);
System.out.println("drawing image...");
System.out.println(g.drawImage(im,insets.left,
insets.top,this)); }
}
再来看看控制台, 可以看到 paint()方法只被执行
了一次 。 这说明图像是被完全加载以后才调用 paint()方
法显示的 。
第 9章 Java在多媒体中的应用
9.4.2 图像生成
AWT除了提供用于描述图像的 java.awt.image类外,
还提供了用于图像处理的 java.awt.image包, 这个包的
所有类几乎都和生产和消费图像有关 。 图像生产者负
责产生图像的位, 而图像消费者用于接收图像的位 。
注:用于描述图像的是 java.awt包中的 Image类, 它
为图像提供引用, 而 java.awt.image包中的类则用于图
像处理, 不要将它们混淆 。
第 9章 Java在多媒体中的应用
在 java.awt.image包中, 提供了图像源生产者接口
ImageProducer,以及用于像素抓取和图像过滤器的消
费者接口 ImageConsumer。
实际上,和图像相关联的位并不存在
java.awt.image中,而是每个图像都和一个
ImageProducer接口相关联,这个 ImageProducer真正负
责生产图像的位。
第 9章 Java在多媒体中的应用
AWT组件除了可以显示图像,还可以创建图像。
要生成一幅图像就必须调用 AWT组件类提供的方法
createImage(ImageProducer)或 CreateImage(int width,int
height)。第一个方法通过给定一个提供图像位的
ImageProducer参数来创建图像;第二个方法则通过指
定图像大小来生成图像。
第 9章 Java在多媒体中的应用
此外, java.awt.Toolkit类也拥有创建图像的能力 。
它提供了三种创建图像的方法:
① createImage(ImageProducer)
② createImage(byte[] bits)
③ createImage(byte[] bits,int offset,int length)
和 AWT一样, Toolkit类在创建图像时, 也可以通
过给定一个 ImageProducer参数来实现 。 另外, 它还提
供了两种方法, 从一个 byte数组创建图像, 该方法是使
用位数组创建图像, 即我们常用的内存图像 。
第 9章 Java在多媒体中的应用
9.4.3 图像处理
在 AWT中, 提供了大量的方法支持图像处理, 特
别是在 java.awt.image包中, 为我们提供了一些十分有
用的图像过滤器 。 这一节将向大家介绍如何使用这些
奇妙的图像过滤器 。
前面已经提到, 生产者接口 ImageProducer用于产
生图像位并把它们传递给图像消费者 。 对于每个 Image
对象, 都有一个和它对应的图像生产者, 其作用是用
来重构图像和生产随时需要的图像位 。
第 9章 Java在多媒体中的应用
图像生产者保持一个图像消费者列表,他们得到
的图像数据都来自图像生产者。 ImageProducer接口提
供用来在列表中增加或删除图像消费者的方法,而且
同时还用于判断一个消费者是否已经向生产者注册。
在 java.awt.image软件包中,有两个类实现
ImageProducer接口,它们是,FilteredImageSource类和
MemoryImageSource类。
第 9章 Java在多媒体中的应用
图像消费者 ImageConsumer接口用于从图像生产者
接收图像数据,java.awt.image包中也提供了两个类实
现 ImageConsumer接口,它们是,ImageFilter类和
PixelGrabber类。
下面我们来介绍如何使用 java.awt.image包中的图像
处理工具 —— 图像过滤器 。
java.awt.image 包提供了下面几种图像过滤器:
● CorpImageFilter:从一副已知图像中裁剪出一个特
殊的矩形, 要裁剪的矩形形状由过滤器的构造器来决
定 。
第 9章 Java在多媒体中的应用
● ReplicateScaleFilter:使用一个简单的算法缩放图像,
例如复制图像数据的行或列进行放大;删除图像数据
的行或列进行缩小 。
● AreaAveragingScaleFilter:是 ReplicateScaleFilter的
一个扩展, 它在缩放时采用了一个比较高级的算法 。
两者的使用方式相同, 但 AreaAveragingSealeFilter缩放
图像的质量要好些 。
第 9章 Java在多媒体中的应用
● RGBImageFilter:是一类抽象过滤器, 其作用是传
输专用像素到它在 RGB颜色模式中的扩展, 用于实现
自定义图像过滤器 。
这里我们主要讨论 CorpImageFilter和
RGBImageFilter的使用。我们先来看一个使用
CropImageFilter实现图像裁减的例子。
第 9章 Java在多媒体中的应用
例 9.10 CropTest.java
import java.awt.*;
import java.awt.image.*;
import java.net.*;
public class CropTest extends Frame {
private Image im;
private Image cropped;
private Insets insets;
private int width,height;
public static void main(String[] agrs)
第 9章 Java在多媒体中的应用
{ CropTest frame = new CropTest();
frame.setVisible(true); }
public CropTest() {
MediaTracker mt = new MediaTracker(this);
im = Toolkit.getDefaultToolkit().getImage("pic.jpg");
mt.addImage(im,0);
try { mt.waitForID(0);}
catch(Exception e) {e.printStackTrace(); }
width = im.getWidth(this);
height = im.getHeight(this);
第 9章 Java在多媒体中的应用
ImageFilter filter = new CropImageFilter(110,5,100,100);
FilteredImageSource fis = new
FilteredImageSource(im.getSource(),filter);
cropped = createImage(fis); }
public void addNotify() {
super.addNotify(); // peer is created here
insets = getInsets();
setBounds(100,100,width+insets.left+120,
height+insets.top); }
第 9章 Java在多媒体中的应用
public void paint(Graphics g) {
g.drawImage(im,insets.left,insets.top,this);
g.drawImage(cropped,width+insets.left+20,insets.top,
this);}
}
上面的程序中,通过创建一个 CropImageFilter的对
象来指定要裁减的区域为左上角是 (100,5),宽和高都
是 100的一个矩形区域。
第 9章 Java在多媒体中的应用
接下来构造一个 FilteredImageSource对象,并通过
Image.getSource()方法得到原图的图像生产者的引用,
传递给 FilteredImageSource的对象。最后,调用
Component.createImage()方法生成裁减后的图像,并将
FilteredImageSource对象作为参数传递给该方法。这是
因为 FilteredImageSource实现了 ImageProducer接口,所
以它可以作为 createImage()方法的合法参数。程序的运
行结果如图 9.9所示。
第 9章 Java在多媒体中的应用
图 9.9
第 9章 Java在多媒体中的应用
RGBImageFilter是一个抽象类, 它定义了如下一
个抽象方法:
int filterRGB(int x,int y,int rgb)
改方法在缺省的 RGB颜色模式中, 向 filterRGB()方
法传递像素的位置和 RGB颜色的一个整数表示, 用于
检验像素的 RGB表示, 返回相同的 RGB整数表示或被
修改的像素颜色表示 。 下面是一个使用 RGBImageFilter
实现自定义的溶解过滤器 DissolveFilter的例子 。
第 9章 Java在多媒体中的应用
例 9.11 RGBImageFilter.java
import java.net.URL;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
public class DissolveFilterTest extends Frame {
Image orig,dissolved;
public DissolveFilterTest() {
super("Dissolve Filter");
第 9章 Java在多媒体中的应用
MediaTracker mt = new MediaTracker(this);
URL url = getClass().getResource("tiger.gif");
try { orig =
createImage((ImageProducer)url.getContent());
mt.addImage(orig,0);
mt.waitForID(0);}
catch(Exception e) {
e.printStackTrace(); }
FilteredImageSource fis = new FilteredImageSource(
orig.getSource(),
第 9章 Java在多媒体中的应用
new DissolveFilter(50));
dissolved = createImage(fis); }
public void update(Graphics g) {
paint(g); }
public static void main(String args[]) {
final Frame f = new DissolveFilterTest();
f.setBounds(100,100,730,380);
f.setVisible(true);
f.addWindowListener(new WindowAdapter()
{
第 9章 Java在多媒体中的应用
public void windowClosing(WindowEvent e) {
f.dispose();
System.exit(0);}});
}
public void paint(Graphics g) {
Insets i = getInsets();
int ow = orig.getWidth(this); // ow = Original
Width
g.drawImage(orig,i.left,i.top,this);
g.drawImage(dissolved,i.left + ow + 20,i.top,this);}
第 9章 Java在多媒体中的应用
}
class DissolveFilter extends RGBImageFilter {
private int alpha;
public DissolveFilter() {
this(0); }
public DissolveFilter(int alpha) {
canFilterIndexColorModel = true;
if(alpha < 0 && alpha > 255)
throw new IllegalArgumentException("bad
alpha");
第 9章 Java在多媒体中的应用
this.alpha = alpha; }
public int filterRGB(int x,int y,int rgb) {
DirectColorModel cm =
(DirectColorModel)ColorModel.getRGBdefault();
int alpha = cm.getAlpha(rgb);
int red = cm.getRed (rgb);
第 9章 Java在多媒体中的应用
int green = cm.getGreen(rgb);
int blue = cm.getBlue (rgb);
alpha = alpha == 0? 0, this.alpha;
return alpha << 24 | red << 16 | green << 8 | blue; }
}
这个程序实现了一个溶解过滤器 DissolveFilter,它
是通过扩展 RGBImageFilter得到的。
第 9章 Java在多媒体中的应用
在 DissolveFilter构造器中,接收被过滤图像中每个
颜色的直接颜色模式中的 alpha值 (直接颜色模式即直接
指明颜色值比特位 )。 alpha值的取值范围是 0~ 255。
alpha值为 0表示该图像是完全透明的,而值 255则表示
图像完全不透明 (即原图 )。将载入的图像中的每个点通
过 DissolveFilter.filterRGB( )处理后,重构图像,就得
到了如图 9.10所示的运行结果。
第 9章 Java在多媒体中的应用
图 9.10
第 9章 Java在多媒体中的应用
9.5 动画图像处理
9.5.1 使用线程设计动画
在 Java中, 实现动画有很多种办法, 但它们实现的
基本原理是一样的, 即在屏幕上画出一系列的帧来造
成运动的视觉效果 。 在此, 我们先构造一个程序的框
架, 再慢慢扩展, 使之功能比较齐备 。
第 9章 Java在多媒体中的应用
为了每秒钟多次更新屏幕, 必须创建一个线程来
实现动画的循环, 这个循环要跟踪当前帧并响应周期
性的屏幕更新要求 。 实现线程的方法有两种:创建一
个类 Thread的派生类, 或在当前类上实现一个 Runnable
接口 。 一个较容易犯的错误是将动画循环放在 paint()中,
这样就会占据主 AWT线程, 而主线程是用于负责所有
的绘图和事件处理的, 这将导致界面对事件响应迟钝 。
下面我们来看一个使用线程实现动画的例子 。
第 9章 Java在多媒体中的应用
例 9.12 Animation.java
import java.awt.*;
public class Animation extends Frame implements Runnable
{ int totalImages = 19;
int currentImage = 0;
int delay = 50;
int x;
Image[] spin;
Thread animator;
第 9章 Java在多媒体中的应用
public static void main(String[] args)
{ Animation frame = new Animation();
frame.setSize(500,150);
frame.setBackground(Color.yellow);
frame.setVisible(true); }
public Animation()
{ spin = new Image[totalImages];
Toolkit defaultTk = Toolkit.getDefaultToolkit();
MediaTracker tracker = new MediaTracker(this);
for (int i = 0; i < totalImages; i++)
第 9章 Java在多媒体中的应用
{ spin[i] = defaultTk.getImage("spin"+i+".gif");
tracker.addImage(spin[i],i);
try {
tracker.waitForID(i);}
catch (InterruptedException e) {
e.printStackTrace(); }
}
x = 0;
animator = new Thread(this);
animator.start();
}
第 9章 Java在多媒体中的应用
public void run()
{ while (Thread.currentThread() == animator)
{ repaint();
try {
Thread.sleep(delay);}
catch (InterruptedException e) {
e.printStackTrace(); }
}
}
第 9章 Java在多媒体中的应用
public void paint(Graphics g)
{ g.drawImage(spin[currentImage],10+x,30,this);
x = (x+5) % 400;
currentImage = ++currentImage % totalImages;}
}
此程序的原理是利用一系列的图片的更替来实现
动画,run()方法中不断的调用 repaint()方法,repaint()
方法又会导致 paint()方法被调用,每次调用 paint()方法
都会绘制一副图片,并且将 currentImage指针移动到下
一幅图片的位置,横坐标也随之平移。这样的效果就
是出现一个不断移动的小人,如图 9.11所示。
第 9章 Java在多媒体中的应用
图 9.11
第 9章 Java在多媒体中的应用
9.5.2 避免闪烁
大家可能已经发现,上例的画面有些闪动。闪烁有
两个原因:一是绘制每一帧花费的时间太长 (因为重绘
时要求的计算量大 ),二是在每次调用 pait()前整个背景
被清除,当在进行下一帧的计算时,用户看到的是背景。
清除背景和绘制图形间的短暂时间被用户看见,就是
闪烁。在有些平台,如 PC机上,闪烁比在 X Window上
明显,这是因为 X Window的图像被缓存过,使得闪烁
的时间比较短。有两种办法可以明显地减弱闪烁:重
载 update()或使用双缓冲。
第 9章 Java在多媒体中的应用
这里我们先讨论重载 update()的方法 。 当 AWT接收
到一个重绘 (repaint)请求时, 它就先调用 update()清除背
景, 而 update()方法又会调用 paint()。 重载 update(),手
动调用 paint()方法, 避免每次重绘时将整个区域清除,
即背景不再自动清除 。 这需要我们自己在 update()中编
写代码来完成 。 在绘制新的图像之前手动将原来的旧
图擦除, 这样可以有效地避免闪烁 。 我们来看修改以
后的例子 。
第 9章 Java在多媒体中的应用
例 9.13 Animation1.java
import java.awt.*;
public class Animation1 extends Frame implements Runnable
{ int totalImages = 19;
int currentImage = 0;
int delay = 50;
int x,x1;
Image[] spin;
Thread animator;
第 9章 Java在多媒体中的应用
public static void main(String[] args)
{ Animation1 frame = new Animation1();
frame.setSize(500,150);
frame.setBackground(Color.yellow);
frame.setVisible(true); }
public Animation1()
{ spin = new Image[totalImages];
Toolkit defaultTk = Toolkit.getDefaultToolkit();
MediaTracker tracker = new MediaTracker(this);
第 9章 Java在多媒体中的应用
for (int i = 0; i < totalImages; i++)
{ spin[i] = defaultTk.getImage("spin"+i+".gif");
tracker.addImage(spin[i],i);
try {
tracker.waitForID(i);}
catch (InterruptedException e) {
e.printStackTrace(); }}
x = 0;
x1 = 0;
animator = new Thread(this);
animator.start();
}
第 9章 Java在多媒体中的应用
public void run()
{while (Thread.currentThread() == animator)
{ repaint();
try {
Thread.sleep(delay);}
catch (InterruptedException e) {
e.printStackTrace(); }}
}
public void update(Graphics g)
第 9章 Java在多媒体中的应用
{ g.setColor(Color.yellow);
g.fillRect(x1,30,
spin[0].getWidth(this),spin[0].getHeight(this));
paint(g); }
public void paint(Graphics g)
{ g.drawImage(spin[currentImage],10+x,30,this);
x1 = x;
x = (x+5) % 400;
currentImage = ++currentImage % totalImages; }
}
第 9章 Java在多媒体中的应用
9.5.3 双缓冲技术
另一种减小帧之间的闪烁的方法就是使用双缓冲,
它在许多动画 Applet中被使用 。 双缓冲技术主要原理是
创建一个后台图像, 将一帧画入图像, 然后调用
drawImage()将整个图像一次画到屏幕上去 。 好处是大
部分绘制是离屏的, 将离屏图像一次绘至屏幕上比直
接在屏幕上绘制要有效得多 。
双缓冲可以使动画平滑, 但有一个缺点:要分配
一张后台图像, 如果此图像相当大, 将需要很大一块
内存 。 当使用双缓冲技术时, 应重载 update()。 下面我
们来看看如何继续修改 Animation实现双缓冲 。
第 9章 Java在多媒体中的应用
例 9.14 Animation2.java
import java.awt.*;
public class Animation2 extends Frame implements Runnable
{ int totalImages = 19;
int currentImage = 0;
int delay = 50;
int x,x1;
Image[] spin;
Thread animator;
Image offscreen;
第 9章 Java在多媒体中的应用
public static void main(String[] args)
{ Animation2 frame = new Animation2();
frame.setSize(500,150);
frame.setBackground(Color.yellow);
frame.setVisible(true); }
public Animation2()
{ spin = new Image[totalImages];
Toolkit defaultTk = Toolkit.getDefaultToolkit();
第 9章 Java在多媒体中的应用
MediaTracker tracker = new MediaTracker(this);
for (int i = 0; i < totalImages; i++)
{ spin[i] = defaultTk.getImage("spin"+i+".gif");
tracker.addImage(spin[i],i);
try {
tracker.waitForID(i);}
catch (InterruptedException e) {
e.printStackTrace(); }}
x = 0;
x1 = 0;
第 9章 Java在多媒体中的应用
animator = new Thread(this);
animator.start();}
public void run()
{ while (Thread.currentThread() == animator)
{ repaint();
try {
Thread.sleep(delay);}
catch (InterruptedException e) {
e.printStackTrace(); }}
}
第 9章 Java在多媒体中的应用
public void update(Graphics g)
{ paint(g); }
public void paint(Graphics g)
{if (offscreen == null)
offscreen = createImage(getSize().width,
getSize().height);
Graphics og = offscreen.getGraphics();
og.setClip(0,0,getSize().width,getSize().height);
og.setColor(Color.yellow);
og.fillRect(x1,30,spin[0].getWidth(this),
第 9章 Java在多媒体中的应用
spin[0].getHeight(this));
og.drawImage(spin[currentImage],10+x,30,this);
super.paint(og);
g.drawImage(offscreen,0,0,null);
x1 = x;
x = (x+5) % 400;
currentImage = ++currentImage % totalImages; }
}
第 9章 Java在多媒体中的应用
程序中先创建了一个图形上下文, 这个图形上下
文并不是在屏幕上显示图像的那一个, 所以也称为离
屏图像 。 将要显示的图片先画到这个图形上下文中,
然后将这个离屏图像一次性贴到屏幕上 。 这样的速度
要比直接在屏幕上画图快的多, 所以对消除闪烁是十
分有效的 。