第4章 Java对多媒体的支持

作者:顾振宇
您可以自由下载本文,但请保留作者信息。

4.2 图像与声音

    与其它语言相比较,如果说Java对图形和文本媒体的支持并不占明显优势的话,那么
Java对图像与声音媒体的支持真可谓是技高一筹,显示图像与播放声音就如同显示一行文
本一样方便。同时,正由于在Java动画中灵活的运用图像和声音媒体,才使得Web页面更
具魅力。

4.2.1 图像文件的显示

    正如上一节所介绍的,Graphics类中确实提供了不少绘制图形的方法,但如果用它们
在applet运行过程中实时地绘制一幅较复杂的图形(例如一条活泼可爱的小狗),就好比
是在用斧头和木块去制造航天飞机。因此,对于复杂图形,大部分都事先用专用的绘图软
件绘制好,或者是用其它截取图像的工具(如扫描仪、视效卡等)获取图像的数据信息,
再将它们按一定的格式存入图像文件。applet运行时,只要找到图像文件存贮的位置,将
它装载到内存里,然后在适当的时机将它显示在屏幕上就可以了。

1. 图像文件的装载

    Java目前所支持的图像文件格式只有两种,它们分别是GIF和JPEG格式(带有.GIF、
.JPG、.JPEG后缀名的文件)。因此若是其它格式的图像文件,就先要将它们转换为这两
种格式。能转换图像格式的软件有很多,如PhotoStyler等。
    Applet类中提供了getImage( )方法用来将准备好的图像文件装载到applet中,但我
们必须首先指明图像文件所存贮的位置。由于Java语言是面向网络应用的,因此文件的存
贮位置并不局限于本地机器的磁盘目录,而大部分情况是直接存取网络中Web服务器上的
图像文件,因而,Java采用URL(Universal Resource Location,统一资源定位器)来定
位图像文件的网络位置。因此,Java专门提供了URL类来管理URL信息(关于该类的详细介
绍见下一章)。
    表示一个URL信息可分为两种形式:
    一种称为绝对URL形式,它指明了网络资源的全路径名。如:

      绝对URL:“http://www.xyz.com/java/imgsample/images/m1.gif”

    另一种称为相对URL形式,分别由基准URL(即base URL)再加上相对于基准URL下的
相对URL这两部分组成,例如上面的例子可表示为:

      基准URL:“http://www.xyz.com/java/imgsample/”
      相对URL:“images/m1.gif”

    现在,我们可以来看一下getImage( )方法的调用格式了:

      Image getImage(URL url) 
      Image getImage(URL url, String name) 

    我们可以发现,这两种调用格式的返回值都是Image对象。确实,Java特别提供了
java.awt.Image类来管理与图像文件有关的信息,因此执行与图像文件有关的操作时不要
忘了import这个类。getImage( )方法的第一种调用格式只需一个URL对象作为参数,这便
是绝对URL。而后一种格式则带有两个参数,第一个参数给出的URL对象是基准URL,第二
个参数是字符串类型,它描述了相对于基准URL下的路径和文件名信息,因此这两个参数
的内容综合在一起就构成了一个绝对URL。例如,下面两种写法所返回的结果是一样的:

      Image img=getImage(new URL("http://www.xyz.com/java/imgsample/images/m1.gif");
      Image img=getImage(new URL("http://www.xyz.com/java/imgsample/"),"images/m1.gif");

    表面看来,好象第一种调用格式较方便一些,但实际上第二种调用格式用得更普遍,
因为这种格式更具灵活性。原来,Applet类中提供了两个方法来帮助我们方便地获取基准
URL对象,它们的调用格式如下:

      URL getDocumentBase( ) 
      URL getCodeBase( ) 

    其中getDocumentBase( )方法返回的基准URL对象代表了包含该applet的HTML文件所
处的目录,例如该文件存贮在"http://www.xyz.com/java/imgsample/m1.html"中,则该
方法就返回"http://www.xyz.com/java/imgsample/"路径。而getCodeBase( )方法返回的
基准URL对象代表了该applet文件(.class文件)所处的目录。它是根据HTML文件的"APPLET"
标记中的CODEBASE属性值计算出来的,若该属性没有设置,则同样返回该HTML文件所处的
目录。
    好了,现在我们应该可以感受到基准URL的灵活性了吧。只要我们写下语句:

      Image img = getImage(getDocumentBase( ),"images/m1.gif");

    那么即使整个imgsample目录移到别处任何地方,也可以正确装载图像文件,而采用
对于绝对URL形式则需要重新修改applet代码并重新编译。

2. 图像文件的显示

    getImage( )方法仅仅是将图像文件从网络上装载进来,交由Image对象管理。那我们
怎样把得到的Image对象中的图像显示在屏幕上呢?这又要回到我们的老朋友Graphics类
中来了,因为Graphics类提供了一个drawImage( )方法,它能完成将Image对象中的图像
显示在屏幕的特定位置上,就象显示文本一样方便。drawImage( )方法的调用格式如下:
      boolean drawImage(Image img, int x, int y, ImageObserver observer)
    其中img参数就是要显示的Image对象。x和y参数是该图像左上角的坐标值。observer
参数则是一个ImageObserver接口(interface),它用来跟踪图像文件装载是否已经完成
的情况,通常我们都将该参数置为this,即传递本对象的引用去实现这个接口。
    除了将图像文件照原样输出以外,drawImage( )方法的另外一种调用格式还能指定图
像显示的区域大小:

      boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) 

    这种格式比第一种格式多了两个参数width和height,即表示图像显示的宽度和高度
。若实际图像的宽度和高度与这两个参数值不一样时,Java系统会自动将它进行缩放,以
适合我们所定的矩形区域。
    有时,我们为了不使图像因缩放而变形失真,可以将原图的宽和高均按相同的比例进
行缩小或放大。那么怎样知道原图的大小呢?只需调用Image类中的两个方法就可以分别
得到原图的宽度和高度。它们的调用格式如下:

      int getWidth(ImageObserver observer)
      int getHeight(ImageObserver observer)

    同drawImage( )方法一样,我们通常用this作为observer的参数值。
    下面的程序段给出了一个显示图像文件的例子,其显示结果如图4-14所示。

import java.awt.Graphics;
import java.awt.Image;
public class Images extends java.applet.Applet{
    Image img;
	public void init(){
		img=getImage(getCodeBase(),"man.gif");
	}
	public void paint(Graphics g){
		int w=img.getWidth(this);
		int h=img.getHeight(this);
		g.drawImage(img,20,10,this);			//原图
		g.drawImage(img,200,10,w/2,h/2,this);		//缩小一半
		g.drawImage(img,20,200,w*2,h/3,this);		//宽扁图
		g.drawImage(img,350,10,w/2,h*2,this);		//瘦高图
	}
}

图4-14 显示图像文件

4.2.2 声音文件的播放

    对声音媒体的直接支持可以说是Java的一大特色,尤其是在动画中配上声音效果,就
可以使人在视觉上和听觉上均得到美的享受,那才叫过瘾。Java中播放声音文件与显示图
像文件一样方便,同样只需要先将声音文件装载进来,然后播放就行了。
    Java目前支持的声音文件只有一种格式,那就是SUN公司的AU格式(.AU文件),也称
为u-law格式。由于AU格式的声音仅有8KHz的采样频率且不支持立体声效果,所以音质不
算太好。唯一的好处就是AU声音文件的尺寸比其它格式小,有利于网上传输。一般,我们
较熟悉的大都是WAV格式的声音文件,因此必须先将它们转换为AU格式(可以选用Goldwave
软件来进行这种格式转换)。
    声音文件准备好以后,就可以考虑将它装载进来并播放。在Applet类中提供的play( )
方法可以将声音文件的装载与播放一并完成,其调用格式如下:

      void play(URL url)
      void play(URL url, String name) 

    可见,play( )方法的调用格式与getImage( )方法是完全一样的,也采用URL来定位
声音文件。例如,某声音文件audio.au与applet文件存放在同一目录下,可以这样写:

      play(getCodeBase( ),"audio.au");

    一旦play( )方法装载了该声音文件,就立即播放。如果找不到指定URL下的声音文件
,play( )方法不返回出错信息,只是听不到想听的声音而已。
    由于play( )方法只能将声音播放一遍,若想循环播放某声音作为背景音乐,就需要
用到功能更强大的AudioClip类,它能更有效地管理声音的播放操作。因为它被定义在
java.applet程序包中,所以使用该类的话,不要忘了在程序头部加上:

      import java.applet.AudioClip;

    为了得到AudioClip对象,我们可以调用Applet类中的getAudioClip( )方法。它能装
载指定URL的声音文件,并返回一个AudioClip对象,其调用格式如下:

      AudioClip getAudioClip(URL url)
      AudioClip getAudioClip(URL url, String name)

    得到AudioClip对象以后,就可以调用AudioClip类中所提供的各种方法来操作其中的
声音数据,这些方法如表4-4所示。
    如果getAudioClip( )方法没有找到所指定的声音文件,就会返回null值。所以,在
调用表4-4中所列的方法前,应该先检查一下得到的AudioClip对象不是null,因为在null
对象上调用上述方法将导致出错。
    如果需要的话,我们还可以在applet中同时装载几个声音文件来一起播放,到时候,
这些声音将混合在一起,就象二重奏一样。另外还有一点要说明的是,如果我们使用
AudioClip对象的loop( )方法来重复播放背景音乐时,千万不要忘记在适当的时候调用
AudioClip对象的stop( )方法来结束放音,否则的话,即使用户离开这一Web页面,该声
音也不会停止,这无疑将会惹恼用户。因此,一般我们都在applet的stop( )方法中添上
停止播放的代码。
    例如,下面这段程序将播放两段声音,一段是连续播放的背景音乐,另一段是讲话录
音。

import java.applet.AudioClip;
public class Audios extends java.applet.Applet{
	AudioClip bgmusic,speak;
	public void init(){
		bgmusic=getAudioClip(getDocumentBase(),"space.au");
		speak=getAudioClip(getDocumentBase(),"intro.au");
	}
	public void start(){
		if(bgmusic!=null)		
			bgmusic.loop();
		if(speak!=null)
			speak.play();
	}
	public void stop(){
		if(bgmusic!=null)
			bgmusic.stop();		//关闭背景音乐,切记。
	}
}